使用 SFINAE 检查全局操作符<<?
我想要几个重载的全局 to_string()
函数,它们采用某种类型的 T
并将其转换为它的字符串表示形式.对于一般情况,我希望能够写:
I want to have several overloaded, global to_string()
functions that take some type T
and convert it to its string representation. For the general case, I want to be able to write:
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
的实现是:
My implementation of has_insertion_operator
so far is:
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和这个.)这似乎有效.但是现在我想要一个 to_string
的重载版本,用于 not 有 operator<<<
但do 的类型> 有自己的to_string()
member 函数,即:
(It borrows from this
and this.)
That seems to work.
But now I want to have an overloaded version of to_string
for types that do not have operator<<
but do have their own to_string()
member function, i.e.:
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.)但是,当我有:
(This part seems to work fine. It's adapted from this.) However, when I have:
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
以便确定全局 operator<<
是否可用?
It seems like SFINAE is not happening. How do I write has_insertion_operator
correctly such that it determines whether a global operator<<
is available?
仅供参考:我使用的是 g++ 4.2.1(在 Mac OS X 上作为 Xcode 的一部分提供).另外,我希望代码只是标准的 C++03,没有 3rd 方库,例如 Boost.
FYI: I'm using g++ 4.2.1 (that which ships as part of Xcode on Mac OS X). Also, I'd like the code to be only standard C++03 without 3rd-party libraries, e.g., Boost.
谢谢!
推荐答案
我应该更忠实于这个的答案.一个有效的实现是:
I should have simply been more faithful to this answer. A working implementation is:
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.
I believe that it does not actually rely on SFINAE.
相关文章