c++ - Variadic Template Dispatcher -
i use variadic templates solve issue using va-args. basically, want call singular function, pass function "command" along variable list of arguments, dispatch arguments function.
i've implemented using tried , true (but not type safe) va_list. here's attempt made @ doing using variadic templates. example doesn't compile below find out why...
#include <iostream> using namespace std; typedef enum cmd_t { cmd_zero, cmd_one, cmd_two, } commands; int cmd0(double a, double b, double c) { cout << "cmd0 " << << ", " << b << ", " << c << endl; return 0; } int cmd1(int a, int b, int c) { cout << "cmd1 " << << ", " << b << ", " << c << endl; return 1; } template<typename... args> int dispatchcommand(commands cmd, args... args) { int stat = 0; switch (cmd) { case cmd_zero: cmd0(args...); break; case cmd_one: cmd1(args...); break; default: stat = -1; break; } return stat; } int main() { int stat; stat = dispatchcommand(cmd_zero, 1, 3.141, 4); stat = dispatchcommand(cmd_one, 5, 6, 7); stat = dispatchcommand(cmd_two, 5, 6, 7, 8, 9); system("pause"); return 0; }
does have idea on how can modify function use variadic templates correctly?
write code that, given function pointer , set of arguments, calls longest prefix of arguments works.
template<class...>struct types{using type=types;}; template<class types0, size_t n, class types1=types<>> struct split; template<class t00, class...t0s, size_t n, class...t1s> struct split<types<t00,t0s...>,n,types<t1s...>>: split<types<t0s...>,n-1,types<t1s...,t00>> {}; template<class...t0s, class...t1s> struct split<types<t0s...>,0,types<t1s...>> { using right=types<t0s...>; using left=types<t1s...>; }; template<class>using void_t=void; template<class sig,class=void> struct valid_call:std::false_type{}; template<class f, class...args> struct valid_call<f(args...), void_t< decltype( std::declval<f>()(std::declval<args>()...) ) >>:std::true_type {}; template<class r, class types> struct prefix_call; template<class r, class...args> struct prefix_call<r, types<args...>> { template<class f, class... extra> std::enable_if_t< valid_call<f(args...)>::value, r > operator()(r default, f f, args&&...args, extra&&...) const { return std::forward<f>(f)(args...); } template<class f, class... extra> std::enable_if_t< !valid_call<f(args...)>::value, r > operator()(r default, f f, args&&...args, extra&&...) const { return prefix_call<r, typename split<types<args...>, sizeof...(args)-1>::left>{}( std::forward<r>(default), std::forward<f>(f), std::forward<args>(args)... ); } }; template<class r> struct prefix_call<r, types<>> { template<class f, class... extra> std::enable_if_t< valid_call<f()>::value, r > operator()(r default, f f, extra&&...) const { return std::forward<f>(f)(); } template<class f, class... extra> std::enable_if_t< !valid_call<f()>::value, r > operator()(r default, f f, extra&&...) const { return std::forward<r>(default); } };
the above code may contain typos.
template<typename... args> int dispatchcommand(commands cmd, args... args) { int stat = 0; switch (cmd) { case cmd_zero: { stat = prefix_call<int, args...>{}(-1, cmd0, std::forward<args>(args)...); } break; case cmd_one: { stat = prefix_call<int, args...>{}(-1, cmd1, std::forward<args>(args)...); } break; default: { stat = -1; } break; } return stat; }
if cmd0
or cmd1
overridden, you'll have use overload set technique.
Comments
Post a Comment