我用我的类作为它的父类中的一个模板参数,而父类使用它的模板参数(不过的sizeof ())。使用子类的基类的模板参数,并为嵌套名指定
,编译器给我:
错误:不完全类型“祈求:: workerClass {又名MyClass的}”嵌套名指定中使用
然而,类文件中被明确定义。我想这是因为子类没有在基类的实例化的时刻实例化,但那种事情发生的CRTP而且也没有问题。
我用的是子类的模板参数的原因是为了做一个不同的函数调用如果子类有,还是没有,具体的功能。
下面是测试的最小码
/* Structure similar to boost's enable if, to use
SFINAE */
template <int X=0, class U = void>
struct test {
typedef U type;
};
enum Commands {
Swim,
Fly
};
/* Structure used for template overloading,
as no partial function template specialization available */
template<Commands T>
struct Param {
};
template <class T>
class Invoker
{
public:
typedef T workerClass;
workerClass *wc() {
return static_cast<workerClass*>(this);
}
template <Commands command>
void invoke() {
invoke2(Param<command>());
}
/* If the child class has those functions, call them */
/* Needs template paramter Y to apply SFINAE */
template<class Y=int>
typename test<sizeof(Y)+sizeof(decltype(&workerClass::fly))>::type
invoke2(Param<Fly>) {
wc()->fly();
}
template<class Y=int>
typename test<sizeof(Y)+sizeof(decltype(&workerClass::swim))>::type
invoke2(Param<Swim>) {
wc()->shoot();
}
template<Commands command>
void invoke2(Param<command>) {
/* Default action */
printf("Default handler for command %d\n", command);
}
};
template <class T, class Inv = Invoker<T> >
class BaseClass : public Inv
{
public:
template<Commands command>
void invoke() {
Inv::template invoke<command>();
}
};
class MyClass : public BaseClass<MyClass>
{
public:
void swim() {
printf("Swimming like a fish!\n");
}
/* void fly(); */
};
void testing() {
MyClass foo;
foo.invoke<Fly>(); /* No 'void fly()' in MyClass, calls the default handler */
foo.invoke<Swim>(); /* Should print the swimming message */
}
错误发生在该行:
typename test<sizeof(Y)+sizeof(decltype(&workerClass::fly))>::type
那么,有没有支持此的编译器,或者是这明确地由标准的规定无效使用模板?我是否必须改变我这样做的方式并找到解决办法? CRTP让我希望代码可能是有效的,但我不确定。
如果这真的是不可能的,那么到底为什么?为什么CRTP工作?
好了,问题很清楚,至少:你正在做一个自我指涉的递归定义:'BaseClass的'需要,因为'decltype的完整'MyClass' '表达式,但是'MyClass'需要一个完整的'BaseClass '作为基类。 –
您需要将特化隐藏在额外的间接层后面,以便它们不作为基类定义的一部分进行评估。把它们放在一个私有的嵌套类型中,并且都可以正常工作。 – ildjarn
正是由于这个原因,CRTP很棘手,所面临的问题很容易理解:基类模板作为类声明的一部分被实例化,但尚未完成(认为类型依赖于什么基本模板可能会添加,所以编译器无法知道派生类型会是什么样的,而无需首先处理基本模板 - 考虑到基本可以添加更改大小的成员属性,或者可以更改基本模板的虚拟成员函数函数声明在派生类型中的含义) –