C++ function dispatch with template parameters -


i'm in process of refactoring large class -- let's call big -- has huge amount of copy-paste code. of copy-paste code exists in switch cases types involved end being different. code switching based on enum member variable of class value known @ runtime.

my attempt fix involves having dispatcher class looks appropriately typed functions via static function called lookup(). functions actual work called go() , have defined in wrapper class template (whose sole parameter runtime enum value being switched on). go() functions may or may not template functions themselves.

here distilled version of code. apologies length, short without losing important context.

#include <cassert>  class big {     public:          enum runtimevalue { a, b };          big(runtimevalue rv) : _rv(rv) { }          bool equals(int i1, int i2)         {             return dispatcher<equals, bool(int, int)>::lookup(_rv)(i1, i2);         }          template<typename t>         bool isconvertibleto(int i)         {             return dispatcher<isconvertibleto, bool(int)>::lookup<t>(_rv)(i);         }      private:          template<runtimevalue rv>         struct equals         {             static bool go(int i1, int i2)             {                 // pretend complicated code relies on rv                 // being compile-time constant.                 return i1 == i2;             }         };          template<runtimevalue rv>         struct isconvertibleto         {             template<typename t>             static bool go(int i)             {                 // pretend complicated code relies on rv                 // being compile-time constant.                 return static_cast<t>(i) == i;             }         };          template<template<runtimevalue> class functionwrapper, typename function>         struct dispatcher         {             static function * lookup(runtimevalue rv)             {                 switch (rv)                 {                     case a: return &functionwrapper<a>::go;                     case b: return &functionwrapper<b>::go;                      default: assert(false); return 0;                 }             }              template<typename t>             static function * lookup(runtimevalue rv)             {                 switch (rv)                 {                     case a: return &functionwrapper<a>::go<t>;                     case b: return &functionwrapper<b>::go<t>;                      default: assert(false); return 0;                 }             }              // , on needed...             template<typename t1, typename t2>             static function * lookup(runtimevalue rv);         };          runtimevalue _rv; };  int main() {     big big(big::a);      assert(big.equals(3, 3));     assert(big.isconvertibleto<char>(123)); } 

this works, except that:

  1. it builds , works fine under visual c++ 9 (2008), under gcc 4.8 results in compilation errors in function-template overload of lookup().
  2. it requires new function-template overload of lookup() written every new number of function template parameters want support in go().
  3. it's cumbersome , confusing use.

here errors occur under gcc:

big.cpp: in static member function 'static function* big::dispatcher<functionwrapper, function>::lookup(big::runtimevalue)': big.cpp(66,65) : error: expected primary-expression before '>' token                          case a: return &functionwrapper<a>::go<t>;                                                                  ^ big.cpp(66,66) : error: expected primary-expression before ';' token                          case a: return &functionwrapper<a>::go<t>;                                                                   ^ big.cpp(67,65) : error: expected primary-expression before '>' token                          case b: return &functionwrapper<b>::go<t>;                                                                  ^ big.cpp(67,66) : error: expected primary-expression before ';' token                          case b: return &functionwrapper<b>::go<t>;                                                                   ^ 

my question twofold:

  1. why failing build under gcc, , how fix it?
  2. is there better (i.e., less cumbersome , confusing) way this?

the code has compilable under visual c++ 9 (2008), can't use c++11-specific.

since go dependent name of template, need use template disambiguator:

case a: return &functionwrapper<a>::template go<t>; //                                  ^^^^^^^^ case b: return &functionwrapper<b>::template go<t>; //                                  ^^^^^^^^ 

this tells compiler parse follows scope resolution operator (::) name of template, , subsequent angular brackets delimiters template arguments.

why failing build under gcc, , how fix it?

because gcc conforming standard, , performs two-phase name lookup, while msvc delays name lookup until instantiation time and, therefore, knows go name of template.

before instantiation information not available, because impossible know t is, , primary template specialized given t go not name of member function template, rather of data member.

this said, expect msvc support template disambiguator anyway, adding should make program compile both on gcc/clang/whatever-conforms-to-the-standard , on msvc.


Comments

Popular posts from this blog

jquery - How can I dynamically add a browser tab? -

keyboard - C++ GetAsyncKeyState alternative -

android - java.net.UnknownHostException(Unable to resolve host “URL”: No address associated with hostname) -