Gio*_*ani 0 c++ templates sfinae
我想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;
}
Run Code Online (Sandbox Code Playgroud)
这种方法的问题在于它不起作用(例如)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);
}
Run Code Online (Sandbox Code Playgroud)
但这不行,因为然后评估模板表达式,arg尚未定义.
template< typename T,
typename = decltype(out << std::declval< T >()) >
decltype(auto) operator<<(T &&arg) {
return out << std::move< T >(arg);
}
Run Code Online (Sandbox Code Playgroud)
这编译,但没有做我想要的,因为它需要T知道类型,而我的问题实际上在于确定如何重载其参数.
我也尝试了更多基于std::enable_ifand std::is_invocable和的模糊条件std::result_of,但是他们引入了许多我无法理解的错误,在这里总结所有尝试可能毫无意义.
有没有办法正确地做这件事?可能使用C++ 14,因此代码库仍然更加落后于compatbile,但如果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;
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
123 次 |
| 最近记录: |