尝试实现类似于此简化示例的 CRTP 时会出现问题:
#include <type_traits>
#include <iostream>
enum ActionTypes {
eInit = 2 << 0,
eUpdate = 2 << 1,
eMultUpdate = 2 << 2
};
template <class Data,
unsigned Actions = eInit|eUpdate|eMultUpdate>
class ActionData
{
template<ActionTypes As /*???*/>
struct action {
static void exec(Data*) { std::cout << "ActionData:: /*dummy*/ exec()\n"; };
static void exec(Data*,int) { std::cout << "ActionData::/*dummy*/ exec(int)\n"; };
};
template<>
struct action < /*???*/ >
{
static void exec(Data*) { /*...*/ };
};
template< >
struct action < /*???*/ >
{
static void exec(Data*, int) { /*...*/ };
};
Data* derived() { return static_cast<Data*>(this); }
protected:
void init() { action<eInit>::exec(derived()); }
void update() { action<eUpdate>::exec(derived()); }
void update(int key) { action<eMultUpdate>::exec(derived()); }
public:
enum Keys { DEFAULT_KEY = -1 };
void call(ActionTypes a, int key = DEFAULT_KEY)
{
switch (a) {
case eInit:
init(); break;
case eUpdate:
if (key == DEFAULT_KEY)
update();
else
case eMultUpdate:
update(key);
}
}
};
class Test : public ActionData<Test, eUpdate>
{
public:
void update() { std::cout << "Test :: update()\n"; }
};
int main()
{
Test actor;
ActionTypes a = eInit;
actor.call(a, 0); // useless here but must be possible.
actor.call(eUpdate, 0);
actor.call(eUpdate);
}
并非所有派生类都实现所需的方法,如果掩码中的相应位未设置,则操作必须选择默认实现。在实践中,基于非类型参数选择不同的专业化是不可能的,并且用类替换它的决定让我难以捉摸。
PS。原始解决方案继承了一个用 C 编写并翻译成 C++ 的大型项目的接口。ActionData 有效功能是 C++98/03 和 tr1 C++11 功能(没有可变参数模板,没有 if constexpr,但存在 enable_if 等)。