I'll start with a c++14 answer then detail how to downgrade c++11.
Suppose you have a list of types:
template<class...>
struct types{using type=types;};
const types<int, double, char> supported_types;
Next we write some utility functions
template<std::size_t I, class...Ts>
using get_type = std::decay_t<decltype(std::get<I>(std::declval<std::tuple<Ts...>&>()))>;
template<std::size_t I, class Types>
struct type_at_helper;
template<std::size_t I, class...Ts>
struct type_at_helper<I, types<Ts...>>{
using type=get_type<I,Ts...>;
};
template<std::size_t I, class Types>
using type_at = typename type_at_helper<I,Types>::type;
Now, type_at<2, decltype(supperted_types)>
is char
.
namespace helper {
template<class F>
using invoker = void(*)(F&&, void*);
template<class F, class Types, std::size_t I>
invoker<F> get_invoker() {
return [](F&& f, void* pdata) {
std::forward<F>(f)( static_cast<type_at<I, Types>*>(pdata) );
};
}
template<class F, class Types, std::size_t...Is>
void dispatch( F&& f, void* data, unsigned type_index, std::index_sequence<Is...>, Types ={} ) {
using pF=std::decay_t<F>*;
using invoker = void(*)(pF, void*);
static const invoker table[]={
get_invoker<F, Types, Is>()...
};
table[type_index]( std::forward<F>(f), data );
}
}
template<class F, class...Ts>
void dispatch( F&& f, void* data, unsigned type_index, types<Ts...> {} ) {
details::dispatch( std::forward<F>(f), data, type_index, std::make_index_sequence<sizeof...(Ts)>{}, types<Ts...>{} );
}
and done.
The downgrade to c++11 simply write make_index_sequence
and index_sequence
. Here is a high quality one, but there are easier ones out there.