我想通过查看是否提供ii
的重载来测试类是否可以流式传输到ostream&
。基于these posts,我尝试使用C ++ 11编写另一个版本。这是我的尝试:
operator<<
但这无法编译:
#include <iostream> #include <type_traits> namespace TEST{ class NotDefined{}; template<typename T> NotDefined& operator << (::std::ostream&, const T&); template <typename T> struct StreamInsertionExists { static std::ostream &s; static T const &t; enum { value = std::is_same<decltype(s << t), NotDefined>() }; }; } struct A{ int val; friend ::std::ostream& operator<<(::std::ostream&, const A&); }; ::std::ostream& operator<<(::std::ostream& os, const A& a) { os << a.val; return os; } struct B{}; int main() { std::cout << TEST::StreamInsertionExists<A>::value << std::endl; std::cout << TEST::StreamInsertionExists<B>::value << std::endl; }
但是,如果我更换线路
test_oper.cpp:40:57: error: reference to overloaded function could not be resolved; did you mean to call it?
std::cout << TEST::StreamInsertionExists<A>::value << std::endl;
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1020:1: note:
possible target for call
endl(basic_ostream<_CharT, _Traits>& __os)
test_oper.cpp:30:17: note: candidate function not viable: no known conversion from 'TEST::NotDefined' to '::std::ostream &'
(aka 'basic_ostream<char> &') for 1st argument
::std::ostream& operator<<(::std::ostream& os, const A& a)
test_oper.cpp:15:15: note: candidate template ignored: couldn't infer template argument 'T'
NotDefined& operator << (::std::ostream&, const T&);
与
enum { value = std::is_same<decltype(s << t), NotDefined>() };
那么一切都会编译。
为什么static const bool value = std::is_same<decltype(s << t), NotDefined>();
和enum
之间存在这样的差异?
答案 0 :(得分:4)
\x9d(\xe7\xae\xbc@\x94x\x0b\xa0*\xd8\x93\
是value
中匿名名称的枚举。当你尝试这样做时:
StreamInsertionExists<T>
编译器正在std::cout << StreamInsertionExists<T>::value;
上进行重载查找。在典型情况下,它会对operator<<(std::ostream&, StreamInsertionExists<T>::E)
进行整体提升,并将其作为enum
进行流式处理。但是,您还定义了此运算符:
int
这是template<typename T>
NotDefined& operator << (std::ostream&, const T&);
比enum
版本(完全匹配与整数提升)更好的匹配,所以它是首选。是的,它是一个功能模板,但只有转换序列匹配时才会使用非模板 - 在这种情况下,它们不会。
因此,这一行:
int
是:
std::cout << TEST::StreamInsertionExists<A>::value << std::endl;
最里面的operator<<(operator<<(std::cout, TEST::StreamInsertionExists<A>::value), std::endl);
来电将使用您的operator<<
模板。因此,下一步是找到适当的函数调用:
NotDefined&
并且operator<<(NotDefined&, std::endl);
没有这样的重载因此错误。
如果您将operator<<
更改为value
,则不存在此问题,因为 bool
完全取消operator<<
:{ {3}}。也就是说,即使使用bool
,您的特征仍然不正确,因为它始终返回bool
。您的false
版本实际上会返回引用,因此您必须对此进行检查。此外,NotDefined
表示不定义,因此您必须翻转标志:
NotDefined&
然而,这特别容易出错。现在static const bool value = !std::is_same<decltype(s << t), NotDefined&>();
而不是无法编译会改为给你一个链接器错误,而cout << B{};
会给你带来与cout << B{} << endl;
相同的令人困惑的重载错误,而不是简单地说明你不能流一个endl
。
你应该更喜欢这样做:
B
答案 1 :(得分:1)
出于某种原因,我不能让Barry的解决方案与VS2013(vc120 pack 3)一起工作,替换失败不会发生,所以stream_insertion_exists :: value总是返回true(任何想法为什么呢?)
根据Metaprograming: Failure of Function Definition Defines a Separate Function,这是一个解决方法:
template <typename T>
auto has_stream_insertion_helper( ... ) // ... to disambiguate call
-> std::false_type;
template <typename T>
auto has_stream_insertion_helper( int ) // int to disambiguate call
-> decltype( std::declval<std::ostream&>() << std::declval<T>(), std::true_type{} );
template <typename T>
using has_stream_insertion = decltype( has_stream_insertion_helper<T>( 0 ) );
class ClassNoStream {};
class ClassHasStream {};
std::ostream& operator<<( std::ostream&, const ClassHasStream& );
static_assert( has_stream_insertion< int >::value, "" );
static_assert( !has_stream_insertion< ClassNoStream >::value, "" );
static_assert( has_stream_insertion< ClassHasStream >::value, "" );