I'm learning how to use SFINAE to my advantage. I'm trying to use it to select the function implementation based on existence of a serialize()
function in an object.
This is the code I use to determine, if the type defines the serialize() function:
template <typename T>
class HasSerialize {
private:
typedef char yes[1];
typedef char no[2];
template <typename C> static yes& test(char[sizeof(&C::serialize)]) ;
template <typename C> static no& test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
However, it seems to give exactly oposite results on GCC and on Clang. Assume the following code:
template<bool T>
class NVPtypeSerializer {
public:
template<typename C>
static xmlChar* serialize(C value) {
// serize() is not available
}
};
template<>
struct NVPtypeSerializer<true> {
public:
template<typename T>
static xmlChar* serialize(T value) {
return value.serialize();
}
};
Which is called like this:
foo = NVPtypeSerializer<HasSerialize<Bar>::value >::serialize(value);
Where the class Bar
doesn't have the serialize()
function. This code compiles fine under Clang 3.1, however on GCC 4.7.1 I get the following errors:
error: ‘class Bar’ has no member named ‘serialize’
If I change the struct NVPtypeSerializer<true>
to struct NVPtypeSerializer<false>
it can be compiled on GCC, but Clang gives the following error:
error: no member named 'serialize' in 'Bar'
Where is the problem? Is it in my code? I'd like to have the code portable as much as possible.
Is this really the code test(char[sizeof(&C::serialize)])
? Note that a declaration of a function that takes an array actually declares a function that takes a pointer:
template <typename C> static yes& test(char[sizeof(&C::serialize)]) ;
That actually means:
template <typename C> static yes& test( char* );
Which incidentally is what makes your call test<C>(0)
compile. I don't think that is the proper way of detecting whether the function exists or not. Google on how to detect whether a member/member function exists in a class using SFINAE.
(A simple solution would be adding an extra defaulted argument --provided that you have a C++11 enabled compiler:
template <typename C, std::size_t = sizeof(&C::serialize)>
static yes& test(int) ;
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With