Skip to content

Instantly share code, notes, and snippets.

@matt-42
Created August 14, 2011 15:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matt-42/1144997 to your computer and use it in GitHub Desktop.
Save matt-42/1144997 to your computer and use it in GitHub Desktop.
C++ test on SFINAE and type lists
#include <cassert>
// Return R
template <typename R, typename A, int (A::*)() const>
struct first
{
typedef R ret;
};
// Meta list basic implementation. -----------------------------
struct null_t {};
template <typename H, typename T>
struct list
{
typedef H head;
typedef T tail;
};
template <typename A, typename B = null_t, typename C = null_t, typename D = null_t>
struct make_list
{
typedef list<A, typename make_list<B, C, D>::ret> ret;
};
#define make_list_4(A, B, C, D) typename make_list<A, B, C, D>::ret
template <> struct make_list<null_t, null_t, null_t, null_t> { typedef null_t ret; };
// -----------------------------------------------------------
// Check if A implements fun.
template <typename A>
struct fun_checker
{
template <typename T>
static typename first<int, T, &T::fun>::ret test(int x);
template <typename T> static char test(...);
enum { val = sizeof(test<A>(0)) == sizeof(int) };
};
// Find the first type of the list A::L that implements
// fun.
template <bool b, typename L, int acc>
struct fun_selector_;
template <typename L, int acc>
struct fun_selector_<false, L, acc>
{
typedef typename L::head H;
typedef typename L::tail T;
enum { val = fun_selector_<fun_checker<H>::val, T, acc + 1>::val };
};
template <int acc>
struct fun_selector_<false, null_t, acc> { enum { val = -1 }; };
template <typename L, int acc>
struct fun_selector_<true, L, acc> { enum { val = acc }; };
template <typename L>
struct fun_selector_helper
{
typedef typename L::head H;
typedef typename L::tail T;
enum { val = fun_selector_<fun_checker<H>::val, T, 0>::val };
};
// Call fun on the ith argument.
// Return 42 if i == -1.
template <int i>
struct fun_;
template <>
struct fun_<0>
{
template <typename A, typename B, typename C, typename D>
static int run(const A& a, const B&, const C&, const D&) { return a.fun(); }
};
template <>
struct fun_<1>
{
template <typename A, typename B, typename C, typename D>
static int run(const A&, const B& b, const C&, const D&) { return b.fun(); }
};
template <>
struct fun_<2>
{
template <typename A, typename B, typename C, typename D>
static int run(const A&, const B&, const C& c, const D&) { return c.fun(); }
};
template <>
struct fun_<3>
{
template <typename A, typename B, typename C, typename D>
static int run(const A&, const B&, const C&, const D& d) { return d.fun(); }
};
template <>
struct fun_<-1>
{
template <typename A, typename B, typename C, typename D>
static int run(const A&, const B&, const C&, const D&) { return 42; }
};
// Call the first element of {a, b} that implements
// a method int fun() const. If none, return 42.
template <typename A, typename B, typename C, typename D>
int fun(const A& a, const B& b, const C& c, const D& d)
{
return fun_<fun_selector_helper<make_list_4(A, B, C, D) >::val>::run(a, b, c, d);
}
struct T
{
int fun() const { return 12; }
};
struct U
{
int fun() const { return 13; }
};
struct V
{
int fun() const { return 42; }
};
int main()
{
T t; U u; V v;
assert(fun(u, t, 2, 3) == 13);
assert(fun(t, t, 2, 3) == 12);
assert(fun('a', 2, "test", 23.23) == 42);
assert(fun('a', 2, t, "test") == 12);
assert(fun(v, t, u, 'e') == 42);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment