我正在尝试创建一个类型特征类,以确定特定类型的T
是否可以通过std::ostream
的<<
操作符进行流式传输。我正在使用一种简单的SFINAE技术。
最终,我尝试评估替换失败的表达式是:
decltype(std::declval<std::ostream>() << std::declval<T>()) ;
我的预期是,给定一个类型为T
的实例t
和一个std::ostream
实例os
,如果表达式os << t
格式错误,则应该发生替换失败。
但是很明显,无论T
类型是什么,这里都不会发生替换失败。即使我只是使用上面的decltype
表达式声明了一个typedef
,在SFINAE的上下文之外,它也可以顺利地编译,即使T
不能与std::ostream
一起使用。
例如:
struct Foo { };
int main()
{
// This compiles fine using GCC 4.9.2
//
typedef decltype(
std::declval<std::ostream>() << std::declval<Foo>()
) foo_type;
}
上面的代码使用GCC 4.9.2可以很好地编译,这并不是我所期望的,因为使用Foo
类型时<<
运算符不会被重载。当然,如果我说:
std::cout << Foo();
..。我得到一个编译器错误。那么,为什么上面的decltype
表达式还要编译呢?
发布于 2016-05-27 18:30:39
如果查看头文件ostream
,就会发现因为std::declval
会生成rvlaue引用,所以实际上有一个匹配的通用operator<<
#if __cplusplus >= 201103L
/**
* @brief Generic inserter for rvalue stream
* @param __os An input stream.
* @param __x A reference to the object being inserted.
* @return os
*
* This is just a forwarding function to allow insertion to
* rvalue streams since they won't bind to the inserter functions
* that take an lvalue reference.
*/
template<typename _CharT, typename _Traits, typename _Tp>
inline basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
{
__os << __x;
return __os;
}
#endif // C++11
这就解释了为什么没有替换失败的原因。然而,这实际上不能与std::cout << Foo()
调用相匹配。以下是编译错误的相关部分:
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/6.1.0/../../../../include/c++/6.1.0/ostream:628:5: note: candidate function [with _CharT = char, _Traits = std::char_traits<char>, _Tp = Foo] not viable: no known conversion from 'ostream' (aka 'basic_ostream<char>') to 'basic_ostream<char, std::char_traits<char> > &&' for 1st argument
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
这里的问题是lhs只能是一个右值引用,但你(显然)在调用中使用了一个左值(即std::cout
)。
https://stackoverflow.com/questions/37480778
复制相似问题