我正在重构一个包含大量Big
复制粘贴代码的大型类——我们称之为它。大部分复制粘贴代码都存在于switch
case
s 中,其中只有所涉及的类型最终不同。代码基于enum
类的成员变量进行切换,该成员变量的值仅在运行时才知道。
我试图解决这个问题包括让一个Dispatcher
类通过一个static
名为lookup()
. 执行实际工作的函数总是被调用go()
并且必须在包装类模板中定义(其唯一参数是enum
当前打开的运行时值)。这些go()
函数本身可能是也可能不是模板函数。
这是代码的提炼版本。对于篇幅,我深表歉意,但在不丢失重要背景的情况下,这是我能得到的尽可能短的内容。
#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 that this is some complicated code that relies on RV
// being a compile-time constant.
return i1 == i2;
}
};
template<RuntimeValue RV>
struct IsConvertibleTo
{
template<typename T>
static bool go(int i)
{
// Pretend that this is some complicated code that relies on RV
// being a 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;
}
}
// And so on as 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));
}
这主要是有效的,除了:
- 它在 Visual C++ 9 (2008) 下可以正常构建和工作,但在 GCC 4.8 下会导致
lookup()
. - 它要求
lookup()
为我们想要支持的每个新数量的函数模板参数编写一个新的函数模板重载go()
。 - 使用起来很麻烦且令人困惑。
以下是在 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>;
^
我的问题是双重的:
- 为什么这无法在 GCC 下构建,我该如何解决?
- 有没有更好的(即不那么麻烦和混乱)的方法来做到这一点?
该代码必须可在 Visual C++ 9 (2008) 下编译,因此我不能使用任何特定于 C++11 的内容。