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
case
s 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:
- it builds , works fine under visual c++ 9 (2008), under gcc 4.8 results in compilation errors in function-template overload of
lookup()
. - it requires new function-template overload of
lookup()
written every new number of function template parameters want support ingo()
. - 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:
- why failing build under gcc, , how fix it?
- 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
Post a Comment