// A third party type I can't change
struct dumb_varient_type {
int to_int() { return 3; }
double to_double() { return 3.14; }
std::string to_string() { return "Pi"; }
};
Напишите вспомогательный тег:
template<class T>struct tag_t{using type=T;};
template<class T>constexpr tag_t<T> tag{};
Затем в пространство имен tag_t
или dumb_variant_type
запишите эти перегрузки: (примечание: не шаблоны, только перегрузки)
int to_type( tag_t<int>, dumb_variant_type const& dumb ) { return dumb.to_int(); }
double to_type( tag_t<double>, dumb_variant_type const& dumb ) { return dumb.to_double(); }
и т. Д.Это делает преобразование вашего тупого варианта более единообразным в общий код.
Теперь мы напишем индексатор:
template<std::size_t...Is>
auto indexer(std::index_sequence<Is...>){
return [](auto&&f){ return f(std::integral_constant<std::size_t,Is>{}... ); };
}
template<std::size_t N>
auto indexer_upto(std::integral_constant<std::size_t,N> ={}){
return indexer(std::make_index_sequence<N>{});
}
Этот помощник избавляет от необходимости разбивать вашу функцию на части.Это дает нам доступ к распакованному пакету индексов по желанию.
При вызове индексатора возвращается лямбда, которая, в свою очередь, принимает лямбду, предоставленную клиентом.Клиентская лямбда вызывается с распакованным пакетом параметров времени компиляции.
Используя это, do_callback
короток и приятен:
template< class R, class... Args >
R do_callback(std::function<R(Args...)> func, std::vector<dumb_varient_type> &args )
{
if(sizeof...(Args) > args.size()) throw std::invalid_argument(); // or whatever
return indexer_upto< sizeof...(Args) >()( []( auto...Is ){
return func( to_type(tag<Args>, args[Is]) ... );
});
}
и готово.Пожалуйста, извините за любые tpyos.