templates - C++ runtime type switching (avoiding switch) -


i've been c++ years have not found yet solution problem have. know how solve awesome.

what have @ moment is:

// client code: switch(currentenumvalue)     {     case myenum::kvalue01:       processdata<myenum::kvalue01>(data);       break;     case myenum::kvalue02:       processdata<myenum::kvalue02>(data);       break;     default:       log("invalid command");       break;     }  // declarations  enum class myenum {kvalue01, kvalue02}; class myclass { // code template <myenum> void processdata(char*); /* implemented somewhere else */ }   template <> void myclass::processdata<myenum::kvalue01>(char* data); /* implemented somewhere else */   myclass <> void myclass::processdata<myenum::kvalue02>(char* data); /* implemented somewhere else */ 

i remove switch because of many reasons. instead of need like: processdata<runtime-decltype(currentenumvalue)>(data);

i know typeid , not mixing compile time , runtime together... despite this, find solution anyway, preferably excluding macros.

this class makes jump table given enum count size based off constructing template , invoking supplied args. assumes enum values start @ 0, , go count-1.

template<class enum, enum count, template<enum>class z> struct magic_switch {   // return value of call magic_switch(args...)   template<class...args>   using r = std::result_of_t<z<enum(0)>(args...)>;   // function pointer jump table:   template<class...args>   using f = r<args...>(*)(args&&...);   // produces single function pointer index , args args...   template<size_t i, class...args>   f<args...> f() const {     using ret = r<args...>;     return +[](args&&...args)->ret{       using invoke=z<enum(i)>;       return invoke{}(std::forward<args>(args)...);     };   }   // builds jump table:   template<class...args, size_t...is>   std::array<f<args...>,size_t(count)>   table( std::index_sequence<is...> ) const {     return {{       f<is, args...>()...     }};   }   template<class...args>   r<args...> operator()(enum n, args&&...args) {     // static jump table case of args...:     static auto jump=table<args...>(std::make_index_sequence<size_t(count)>{});     // nth entry in jump table, , invoke it:     return jump[size_t(n)](std::forward<args>(args)...);   } }; 

then if have enum:

enum class abc_enum { a, b, c, count }; 

and function object template:

template<abc_enum e> struct stuff {   void operator()() const {     std::cout << (int)e << '\n';   } }; 

you can dispatch:

magic_switch<abc_enum, abc_enum::count, stuff>{}(abc_enum::b); 

in case, within template stuff, enum value compile time constant. call run time constant.

overhead should similar switch statement, or vtable call, depending on compiler optimization wise.

live example.

note setting enum std::size_t valid.

in c++11 need make_index_sequence , index_sequence:

template<size_t...> struct index_sequence {}; namespace details {   template<size_t count, size_t...szs>   struct sequence_maker : sequence_maker<count-1, count-1, szs...> {};   template<size_t...szs>   struct sequence_maker<0,szs...> {     using type = index_sequence<szs...>;   }; } template<size_t count> using make_index_sequence=typename details::sequence_maker<count>::type; template<class...ts> using index_sequence_for=make_index_sequence<sizeof...(ts)>; 

and alias:

template<class sig> using result_of_t=typename std::result_of<sig>::type; 

then strip std:: off use in above code.

live example.


Comments

Popular posts from this blog

Magento/PHP - Get phones on all members in a customer group -

php - .htaccess mod_rewrite for dynamic url which has domain names -

Website Login Issue developed in magento -