仅当返回表达式有效时才启用模板
Enable template only if the return expression is valid
我想用这种风格在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
和std::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;
};
演示
std::endl
没有重载。这是一个声明如下的函数模板:
template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& endl( std::basic_ostream<CharT, Traits>& os );
它直接适用于std::ostream
的原因是适当的operator <<
(流操纵器的(是一个常规成员函数(尽管是从char
的basic_ostream
模板生成的(。它期望混凝土机械手类型。模板参数推导可以与此参数类型一起使用,以推导出正确endl
专用化的参数。
由于您似乎只支持std::ostream
,因此@Jarod42答案中的解决方案是要走的路。
相关文章:
- 编译时未启用intel oneApi CUDA支持
- 欧拉项目#8答案是大以获得有效答案
- 调整大小后指向元素值的指针unordered_map有效?
- 为什么是0;C++中的有效语句
- 最高有效数字侧的第N位
- GCC对可能有效的代码抛出init list生存期警告
- 有效地使用std::unordered_map来插入或增加键的值
- c++中O(n^(1/3))中一个数的除数的有效计数
- OpenGL在启用深度测试时不会丢弃我的碎片
- 使用无符号字符数组有效存储内存
- 自定义先决条件对移动分配运算符有效吗
- Visual C++GC接口如何启用它以及要包含哪个库
- 如何在自定义类中启用'auto loops'?
- 为什么将值返回函数传递给重载=运算符对运算符函数有效,而对其他运算符无效
- 根据某个函数是否存在启用模板
- 有哪些有效的方法可以消除一组 100 万个字符串>重复数据?
- 为什么这种直接初始化有效?(C++17)
- 递归函数有效,但无法记忆
- 仅当返回表达式有效时才启用模板
- 仅当启用了嗅探器 - 加密响应内容时,curl 才有效