我正在重构一个大类——我们称之为Big
——有大量的复制粘贴代码。大部分复制粘贴代码存在于switch
case
只有涉及的类型最终不同。该代码是基于一个切换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 的内容。