c++ - fallback to alternate function when templated function instantiation fails -


i need store pointers instanced template functions , when function cannot instanced store pointer empty function instead. looked sfinae dont think applies here.

struct staticentity {     double position; };  struct dynamicentity {     double position;     double speed; };  class movesystem { public:     template <typename t>     void update(t& entity, double dt) {         entity.position += entity.speed*dt;     } };  typedef void (*updateentitiesfunc)(void* system, void* entity, double dt);  template <typename s, typename e> static void update(void* system, void* entity, double dt) {     // here if inner function cannot instanced skip , "nothing" instead     ((s*)system)->update(*(e*)entity, dt); }  int main() {     updateentitiesfunc uf = update<movesystem, dynamicentity>;     updateentitiesfunc uf2 = update<movesystem, staticentity>;     //^ not compile     //  gives error: 'struct staticentity' has no member named 'speed'     //  compile , contain pointer empty function     return 0; } 

it solvable template magic cant figure out. ideally without adding complexity both entity , system classes.

design motivation:

for entity , system types want create static array of function pointers:

updateentitiesfunc funcs[entitytypes::gettypescount()][systemtypes::gettypescount()]; 

and @ runtime call correct function type-ids:

funcs[entity->gettypeid()][system->gettypeid()](&system, &entity, dt); 

at runtime check if entity compatible system runtime information. function pointers must registered entity-system pairs @ compile time, though not compatible. wanted create no-op functions.

first, metaprogramming boilerplate:

namespace details {   template<class...>struct voider{using type=void;};   template<class...ts>using void_t=typename voider<ts...>::type;    template<template<class...>class z, class, class...ts>   struct can_apply:     std::false_type   {};   template<template<class...>class z, class...ts>   struct can_apply<z, void_t<z<ts...>>, ts...>:     std::true_type   {}; } template<template<class...>class z, class...ts> using can_apply=details::can_apply<z,void,ts...>; 

now, can detect properties:

template<class t> using speed_t = decltype(std::declval<t>().speed); template<class t> using position_t = decltype(std::declval<t>().position);  template<class t> using has_speed = can_apply<speed_t, t>; template<class t> using has_position = can_apply<position_t, t>;  template<class s, class e> using update_call_t = decltype( std::declval<s>().update( std::declval<e>(), 0.0 ) );  template<class s, class e> using has_update = can_apply< update_call_t, s, e >; 

and have 3 traits, has_position, has_update , has_speed useful.

now fix movesystem:

struct movesystem {   template <class t>   std::enable_if_t< has_speed<t&>{} && has_position<t&>{} >   update(t& entity, double dt) {     entity.position += entity.speed*dt;   } }; 

next, modify update:

namespace updates {   template<class s, class e>   std::enable_if_t< has_update<s,e>{} >   update(s* system, e* entity, double dt ) {     system->update(*entity, dt);   }   void update(void*, void*, double) {} } template<class s, class e> void update(void* system, void* entity, double dt) {   using updates::update;   update(static_cast<s*>(system), static_cast<e*>(entity), dt ); } 

to check .update method working parameters.

i adl-enabled code such if class has friend void update( s*, e*, double ) work.

this sfinae work. note adding more properties once have can_apply pretty easy. make alias generates type works if property satisfied, write can_apply alias converts application compile-time boolean test.

as aside, msvc2015 not c++11 compiler, in cannot compile above code. in msvc have track down proprietary extensions equivalent of above code. involves writing has_position , other traits differently. call failure obey c++11 standard in case inability "expression sfinae".

note above uses handful of c++14 features. replace std::enable_if_t<??> typename std::enable_if<??>::type, replace has_position<??>{} has_position<??>::value , similar other changes if compiler doesn't support it.


Comments

Popular posts from this blog

python - No exponential form of the z-axis in matplotlib-3D-plots -

php - Best Light server (Linux + Web server + Database) for Raspberry Pi -

c# - "Newtonsoft.Json.JsonSerializationException unable to find constructor to use for types" error when deserializing class -