Jos*_*vin 6 c++ sfinae enable-if c++11 c++14
我正在尝试定义一个has_ostream_operator<T>
SFINAE测试,以检查我是否可以cout一个给定的类型.我有它工作,但只有在我的定义中has_ostream_operator
我称之为operator<<
方法而不是作为中缀运算符.换句话说,这有效:
decltype(std::declval<std::ostream>().operator<<(std::declval<T>()))>
这不是:
decltype(std::declval<std::ostream>() << std::declval<T>())>
下面的测试用例(也可以参见http://coliru.stacked-crooked.com/a/d257d9d6e0f3f6d9).请注意,我包含了void_t的定义,因为我只在C++ 14上.
#include <iostream>
namespace std {
template<class...>
using void_t = void;
}
template<class, class = std::void_t<>>
struct has_ostream_operator : std::false_type {};
template<class T>
struct has_ostream_operator<
T,
std::void_t<
decltype(
std::declval<std::ostream>().operator<<(std::declval<T>()))>>
: std::true_type {};
struct Foo {};
template<class X>
void print(
const X& x,
std::enable_if_t<has_ostream_operator<X>::value>* = 0)
{
std::cout << x;
}
template<class X>
void print(
const X&,
std::enable_if_t<!has_ostream_operator<X>::value>* = 0)
{
std::cout << "(no ostream operator<< implementation)";
}
int main()
{
print(3); // works fine
print(Foo()); // this errors when using infix operator version
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我假设你的"中缀"版本使用了这个表达式:
std::declval<std::ostream>() << std::declval<T>()
Run Code Online (Sandbox Code Playgroud)
匹配的原因Foo
是因为第一部分declval<ostream>()
产生了一个类型的右值ostream&&
.这与非会员匹配operator<<
:
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
Run Code Online (Sandbox Code Playgroud)
这种过载只会转发呼叫:
给定对输出流对象(相当于
os << value
)的rvalue引用,调用适当的插入运算符.
您应该直接检查它.所有重载采取ostream
由左值引用,所以你应该测试过:
std::declval<std::ostream&>() << std::declval<T>()
Run Code Online (Sandbox Code Playgroud)
你需要
std::declval<std::ostream&>() << std::declval<T>()
// ^
Run Code Online (Sandbox Code Playgroud)
std::declval<std::ostream>()
是一个价值; 你正在operator<<
为rvalue流击中全部重载.