Skip to content

Instantly share code, notes, and snippets.

@Jiwan
Created October 29, 2015 12:09
Show Gist options
  • Save Jiwan/2573fc47e4fa5025306b to your computer and use it in GitHub Desktop.
Save Jiwan/2573fc47e4fa5025306b to your computer and use it in GitHub Desktop.
C++98 SFINAE usage for serialization
#include <iostream>
struct A {};
std::string to_string(const A&)
{
return "I am a A!";
}
// Type B with a serialize method.
struct B
{
std::string serialize() const
{
return "I am a B!";
}
};
// Type C with a "wrong" serialize member (not a method) and a to_string overload.
struct C
{
std::string serialize;
};
std::string to_string(const C&)
{
return "I am a C!";
}
struct D : A
{
std::string serialize() const
{
return "I am a D!";
}
};
struct E
{
struct Functor
{
std::string operator()(){
return "I am a E!";
}
};
Functor serialize;
};
// Structures are good as they expose everything in public!
template <class T> struct hasSerialize
{
// For the compile time comparison.
typedef char yes[1];
typedef yes no[2];
// This helper struct permits us to check two properties of a template argument.
template <typename U, U u> struct reallyHas;
// Two overloads for yes: one if for the signature of a normal method, one is for the signature of a const method.
template <typename C> static yes& test(reallyHas<std::string (C::*)(), &C::serialize>* /*unused*/) { }
template <typename C> static yes& test(reallyHas<std::string (C::*)() const, &C::serialize>* /*unused*/) { }
// The famous C++ sink-hole.
// Note that sink-hole must be templated too as we are testing test<T>(0).
template <typename> static no& test(...) { /* dark matter */ }
// The constant used as a return value for the test.
enum { value = sizeof(test<T>(0)) == sizeof(yes) };
};
template <class T> bool testHasSerialize(const T& /*t*/) { return hasSerialize<T>::value; }
template<bool B, class T = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };
template <class T> typename enable_if<hasSerialize<T>::value, std::string>::type serialize(const T& obj)
{
return obj.serialize();
}
template <class T> typename enable_if<!hasSerialize<T>::value, std::string>::type serialize(const T& obj)
{
return to_string(obj);
}
int main() {
A a;
B b;
C c;
std::cout << serialize(a) << std::endl;
std::cout << serialize(b) << std::endl;
std::cout << serialize(c) << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment