我想有几个重载的全局to_string()函数,它们采用某种类型T并将其转换为其字符串表示形式.对于一般情况,我希望能够写: templatetypename T,class OutputStringType inlinetypename enable_if!std::is_pointerT
template<typename T,class OutputStringType> inline typename enable_if<!std::is_pointer<T>::value && has_insertion_operator<T>::value, void>::type to_string( T const &t, OutputStringType *out ) { std::ostringstream o; o << t; *out = o.str(); }
到目前为止,我对has_insertion_operator的实现是:
struct sfinae_base { typedef char yes[1]; typedef char no[2]; }; template<typename T> struct has_insertion_operator : sfinae_base { template<typename U> static yes& test( U& ); template<typename U> static no& test(...); static std::ostream &s; static T const &t; static bool const value = sizeof( test( s << t ) ) == sizeof( yes ); // line 48 };
(它借鉴了this
和this.)
这似乎有效.
但是现在我想为没有运算符<<的类型设置一个重载版本的to_string.但是有自己的to_string()成员函数,即:
template<class T,class OutputStringType> inline typename enable_if<!has_insertion_operator<T>::value && has_to_string<T,std::string (T::*)() const>::value, void>::type to_string( T const &t, OutputStringType *out ) { *out = t.to_string(); }
has_to_string的实现是:
#define DECL_HAS_MEM_FN(FN_NAME) \ template<typename T,typename S> \ struct has_##FN_NAME : sfinae_base { \ template<typename SignatureType,SignatureType> struct type_check; \ template<class U> static yes& test(type_check<S,&U::FN_NAME>*); \ template<class U> static no& test(...); \ static bool const value = sizeof( test<T>(0) ) == sizeof( yes ); \ } DECL_HAS_MEM_FN( to_string );
(这部分似乎工作正常.它改编自this.)
但是,当我有:
struct S { string to_string() const { return "42"; } }; int main() { string buf; S s; to_string( s, &buf ); // line 104 }
我明白了:
foo.cpp: In instantiation of ‘const bool has_insertion_operator<S>::value’: foo.cpp:104: instantiated from here foo.cpp:48: error: no match for ‘operator<<’ in ‘has_insertion_operator<S>::s << has_insertion_operator<S>::t’
似乎SFINAE没有发生.如何正确编写has_insertion_operator,以确定是否为全局运算符<<可以吗? 仅供参考:我正在使用g 4.2.1(在Mac OS X上作为Xcode的一部分提供).
此外,我希望代码只是没有第三方库的标准C 03,例如Boost.
谢谢!
我应该更忠实于 this答案.一个有效的实施是:
namespace has_insertion_operator_impl { typedef char no; typedef char yes[2]; struct any_t { template<typename T> any_t( T const& ); }; no operator<<( std::ostream const&, any_t const& ); yes& test( std::ostream& ); no test( no ); template<typename T> struct has_insertion_operator { static std::ostream &s; static T const &t; static bool const value = sizeof( test(s << t) ) == sizeof( yes ); }; } template<typename T> struct has_insertion_operator : has_insertion_operator_impl::has_insertion_operator<T> { };
我相信它实际上并不依赖于SFINAE.