Chcę mieć kilka przeciążonych, globalnych funkcji to_string()
, które pobierają pewien typ T
i przekształcają go na jego reprezentację ciągów. W ogólnym przypadku, chcę być w stanie napisać:Używanie SFINAE do sprawdzania globalnego operatora <<?
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();
}
Moja implementacja has_insertion_operator
tak daleko jest:
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
};
(pożycza on z this i this.) To wydaje się działać . Ale teraz chcę mieć przeciążony wersję to_string
dla typów, które wykonują nie mieć operator<<
ale zrobić mają własne to_string()
członek funkcję, a mianowicie:
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();
}
Realizacja has_to_string
jest:
#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);
(Ta część działa dobrze, została zaadaptowana z this.) Jednak kiedy mam:
struct S {
string to_string() const {
return "42";
}
};
int main() {
string buf;
S s;
to_string(s, &buf); // line 104
}
uzyskać:
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’
Wydaje się SFINAE nie dzieje. Jak poprawnie napisać has_insertion_operator
, aby określić, czy dostępny jest globalny operator<<
?
FYI: Używam g ++ 4.2.1 (który jest dostarczany jako część Xcode na Mac OS X). Również chciałbym, aby kod był tylko standardowym C++ 03 bez bibliotek 3rd party, np. Boost.
Dzięki!
To wszystko na pewno możliwe, ale * dlaczego *? – Potatoswatter
@Potatoswatter: dlaczego nie jest ważne. Proszę przyjąć, że przez resztę mojego projektu wiem, co robię. Jeśli musisz wiedzieć, jest to część struktury do przekazywania parametrów dowolnego typu, aby utworzyć część zlokalizowanego komunikatu o błędzie.Szczegóły wszystkich, które są niepotrzebne na to pytanie. Jeśli wiesz, jak to zrobić, odpowiedz na pytanie. Byłoby to bardzo doceniane. –
Dlaczego zawsze jest ważne. – GManNickG