C++ CRTP和动态多态编译错误

C++ CRTP和动态多态编译错误,c++,templates,polymorphism,standards,crtp,C++,Templates,Polymorphism,Standards,Crtp,在Clang3.0、GCC4.7和VisualStudio2008上测试 第一个解决方案: Return type of virtual function 'foo' is not covariant with the return type of the function it overrides ('C *' is not derived from 'A *') C类:公共A,公共B{} 在VisualStudio下编译,并警告B已经是a的子级,并且不在带有初始错误的clang下编译 另

在Clang3.0、GCC4.7和VisualStudio2008上测试

第一个解决方案:

Return type of virtual function 'foo' is not covariant with the return type of the function it overrides ('C *' is not derived from 'A *')
C类:公共A,公共B{}
在VisualStudio下编译,并警告B已经是a的子级,并且不在带有初始错误的clang下编译

另一个解决方法:

class C : public A, public B<C> {}
D类:公共A{}
C类:公共B{}
解决了不完整性问题,但我无法计算出我将拥有多少个实例。直觉告诉我A是虚拟的,因此应该只有一个

此外,此解决方法还会创建不可读的代码


标准对这种情况有何规定?这段代码应该编译吗?如果不是,原因是什么?

您的虚拟函数
A::foo()
返回一个
A*
,而用于覆盖它的函数
B::foo()
返回一个
C*

这在理论上确实尊重协方差原理,因为
C
确实是(源自)a的一个特化,但在实例化的时候,这是未知的,因为
C
是一个不完整的类型

重新考虑您的设计的一种可能方法是将
A
也作为类模板,并让
B
T
的模板参数传播到
A

class D : public A {}
class C : public B<D> {}
模板
甲级{
虚拟T*foo()=0;
};
模板
B类:公共A{
虚拟T*foo(){return nullptr;}
};
关于您的解决方案:

class C : public A, public B<C> {}
标准对这种情况有何规定?这段代码应该编译吗?若否,原因为何

它不应该编译,因为在实例化
B
时,仅仅使
C
成为
A
类型的两个不同的基本子对象(注意,在
C
内部,您将得到
A
类型)的事实也不能使
C
成为一个完整的类型。根据C++11标准第9.2/2段:

在类说明符的结尾处,类被视为完全定义的对象类型(3.9)(或完全类型)。。 在类成员规范中,类在函数体中被认为是完整的, 默认参数,以及非静态数据成员的大括号或相等初始值设定项(包括 嵌套类)。否则,在其自身的类成员规范中,它被视为不完整的


记住
C
在它的基列表中是不完整的总是好的。不幸的是,这打破了这段代码的唯一目的:创建多态基类A。函数B::foo(),它要覆盖它,返回一个B*——我读错了吗,或者是
B::foo()
返回
C*
?@ulidtko:Correct,那是我的错误。谢谢。另外,我想在答案中看到的是为什么
C
不是一个完整的类型。(它看起来被完全定义了,所以,嗯……见鬼。)@ulidtko:那是因为我引用的标准中的一段。类类型只有在关闭
}
后才完成。这里,
B
在满足关闭
}
之前被实例化。因此,
C
是不完整的,编译器有权不知道它来自
A
。这就是错误的原因,即不尊重协方差。
template<typename T>
class A {
    virtual T* foo() = 0;
};

template<class T>
class B : public A<T> {
    virtual T* foo() { return nullptr; }
};