#include <type_traits>

template<typename... Types>
struct TypeList {};

template<typename T, typename List, typename=void>
struct IndexOf;

template<typename T, typename First, typename... Types>
struct IndexOf<T, TypeList<First, Types...>,
  typename std::enable_if<
    std::is_same< T, First >::value
  >::type
> {
  enum {value = 0};
};

template<typename T, typename First, typename... Types>
struct IndexOf<T, TypeList<First, Types...>,
  typename std::enable_if<
    !std::is_same< T, First >::value
  >::type
> {
  enum {value = 1+IndexOf<T, TypeList<Types...>>::value};
};

template<size_t n, typename List>
struct TypeAt;

template<size_t n, typename First, typename... Types>
struct TypeAt<n, TypeList<First, Types...>> {
    typedef typename TypeAt<n-1, TypeList<Types...>>::type type;
};

template<typename First, typename... Types>
struct TypeAt<0, TypeList<First, Types...>> {
    typedef First type;
};

template<typename Functor, typename List>
struct TypeDispatch {
    struct Helper {
        Helper( Functor f_ ):f(f_) {}
        Functor f;
        template<size_t n>
        void Call() {
            typedef typename TypeAt<n, List>::type target_type;
            f.template Call<target_type>();
        }
    };
};

template<size_t max>
struct RuntimeSwitch {
    template<typename Functor>
    static bool Call( size_t n, Functor f ) {
        if (n == max) {
            f.template Call<max>();
            return true;
        } else {
            return RuntimeSwitch<max-1>::template Call( n, f );
        }
    }
};

template<>
struct RuntimeSwitch< size_t(-1) > {
    template<typename Functor>
    static bool Call( size_t n, Functor f ) {
        return false;
    }
};

template<typename List>
struct DynamicTypeDispatch;

template<typename... Types>
struct DynamicTypeDispatch<TypeList<Types...>> {
    template<typename Functor>
    static bool Call( size_t n, Functor f ) {
        typedef TypeDispatch<Functor, TypeList<Types...>> typeDispatch;
        typedef typename typeDispatch::Helper typeCaller;
        return RuntimeSwitch<sizeof...(Types)-1>::Call(n, typeCaller(f));
    }
};

#include <iostream>
#include <string>
struct Test {
    std::string s;
    Test( std::string s_ ):s(s_) {}
    template<typename T>
    void Call() {
        std::cout << sizeof(T) << " == " << s.c_str() << " I hope\n";
    }
};
int main()
{
    typedef TypeList<int, double> TestList;
    DynamicTypeDispatch<TestList>::Call( 0, Test("4") );
    DynamicTypeDispatch<TestList>::Call( 1, Test("8") );
}

