Skip to content

Instantly share code, notes, and snippets.

@Jiwan Jiwan/main.cpp
Created Oct 31, 2015

Embed
What would you like to do?
C++ 14 example SFINAE!
#include <boost/hana.hpp>
#include <iostream>
#include <type_traits>
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;
};
template <typename UnnamedType> struct container
{
// Let's put the test in private.
private:
// We use std::declval to 'recreate' an object of 'UnnamedType'.
// We use std::declval to also 'recreate' an object of type 'Param'.
// We can use both of these recreated objects to test the validity!
template <typename Param> constexpr auto test_validity(int /* unused */)
-> decltype(std::declval<UnnamedType>()(std::declval<Param>()), std::true_type())
{
// If substitution didn't fail, we can return a true_type.
return std::true_type();
}
template <typename Param> constexpr std::false_type test_validity(...)
{
// Our sink-hole returns a false_type.
return std::false_type();
}
public:
// A public operator() that accept the argument we wish to test onto the UnnamedType.
// Notice that the return type is automatic!
template <typename Param> constexpr auto operator()(const Param& p)
{
// The argument is forwarded to one of the two overloads.
// The SFINAE on the 'true_type' will come into play to dispatch.
return test_validity<Param>(int());
}
};
template <typename UnnamedType> constexpr auto is_valid(const UnnamedType& t)
{
return container<UnnamedType>();
}
// Check if a type has a serialize method.
auto hasSerialize = is_valid([](auto&& x) -> decltype(x.serialize()) { });
template <class T> auto serialize(T& obj) -> typename std::enable_if<decltype(hasSerialize(obj))::value, std::string>::type
{
return obj.serialize();
}
template <class T> auto serialize(T& obj) -> typename std::enable_if<!decltype(hasSerialize(obj))::value, std::string>::type
{
return to_string(obj);
}
int main() {
A a;
B b;
C c;
D d;
E e;
std::cout << serialize(a) << std::endl;
std::cout << serialize(b) << std::endl;
std::cout << serialize(c) << std::endl;
std::cout << serialize(d) << std::endl;
std::cout << serialize(e) << std::endl;
return 0;
}
@blaz-kranjc

This comment has been minimized.

Copy link

commented Nov 12, 2016

boost/hana.hpp is not actually used in this gist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.