c++ - 仅当返回表达式有效时才启用模板
问题描述
我想用std::ostream
这种风格写一个包装器:
#include <iostream>
struct OstreamWrapper {
OstreamWrapper(std::ostream &out) : out(out) {}
template< typename T >
decltype(auto) operator<<(T &&arg) {
return out << std::move< T >(arg);
}
std::ostream &out;
};
int main() {
OstreamWrapper wrap(std::cout);
wrap << "Hello, world!"; // This works
wrap << std::endl; // This does not work
return 0;
}
这种方法的问题在于(例如)它不适用于std::endl
,因为(据我所知)std::endl
是重载的,并且编译器在评估模板时不知道如何解决重载。
我相信这种情况可以通过一些聪明的 SFINAE 来解决,但我找不到可行的方法。我认为我需要类似“仅在cout << arg
格式良好的表达式时启用此模板”之类的东西,但我不知道如何表达。
例如,我试过这个:
template< typename T,
typename = decltype(out << arg) >
decltype(auto) operator<<(T &&arg) {
return out << std::move< T >(arg);
}
但这不行,因为模板表达式被评估, arg 尚未定义。
template< typename T,
typename = decltype(out << std::declval< T >()) >
decltype(auto) operator<<(T &&arg) {
return out << std::move< T >(arg);
}
这可以编译,但不符合我的要求,因为它需要T
知道类型,而我的问题实际上在于确定如何重载其参数。
我也尝试过基于std::enable_if
andstd::is_invocable
和的更晦涩的条件std::result_of
,但是它们引入了很多我无法理解的错误,在这里总结所有尝试可能毫无意义。
有没有办法正确地做这件事?可能使用 C++14,因此代码库仍然更加向后兼容,但如果需要 C++17,也可以。
解决方案
您可以将重载添加到强制类型(因此选择了唯一的可用重载):
struct OstreamWrapper {
explicit OstreamWrapper(std::ostream &out) : out(out) {}
template< typename T >
decltype(auto) operator<<(T &&arg) {
return out << std::forward<T>(arg);
}
decltype(auto) operator<<(std::ostream& (&arg)(std::ostream&)) {
return out << arg;
}
std::ostream &out;
};
推荐阅读
- devops - 如何下载 Artifactory 中附加构建的所有工件?
- c# - 我在颤振应用程序中遇到“HubConnection.connectionClosed(null) 在状态 HubConnectionState.connected 时调用”问题,用于连接 signalR 集线器
- redis - 如果成员的分数**未**更改(不使用 Lua),我可以从 Redis 排序集中删除成员吗?
- arrays - 以太坊 Solidity 中的 UnimplementedFeatureError
- python - 如何检测whatsapp中的通知以触发python中的操作?
- python - 我想用关键字()函数获取关键字来搜索谷歌图片。我该如何解决
- python - Tetgen 表达式 -d 意外输出
- visual-studio-code - VS Code 使用 snap 安装但未显示
- angular - 我需要将 ddmmyyyy 输入转换为 dd/mm/yyyy 日期格式。我的 html 文件和 ts 文件如下所示
- go - 未“选择”的频道会怎样?