CRTP和动态多态编译错误 [英] CRTP and dynamic polymorphism compile error
问题描述
class A {
virtual A * foo()= 0;
};
template< class T>
class B:public A {
virtual T * foo(){return nullptr; }
};
class C:public B< C> {
};
这是可能性混合复合模式和好奇地重复模板模式。我得到以下错误:
虚函数的返回类型'foo'不与它覆盖的函数的返回类型('C *'不是从'A *'派生的)
在clang 3.0,gcc 4.7 and visual studio 2008。
第一个解决方案:
public A,public B< {}
在visual studio下编译,警告B已经是A的子节点,
$ b
另一种解决方法:
class D:public A {}
class C:public B< D> {}
解决了不完整性问题,但我不知道有多少A个实例。直觉告诉我,A是虚拟的,因此应该只有一个。
此解决方法创建不可读代码。
标准对这种情况说明了什么?这个代码应该编译吗? c> A :: foo()
$
c>返回一个 A *
,而函数 B
它返回一个 C *
。
这在理论上是尊重协方差的原理,因为 C
确实是(派生自) A
的特殊化,但在实例化的时候,这是未知的,因为 C
是不完整的类型。
重新设计一个可能的方式是让 A
一个类模板,并让 B
将 T
的模板参数传播到 A
:
template< typename T&
class A {
virtual T * foo()= 0;
};
template< class T>
class B:public A< T> {
virtual T * foo(){return nullptr; }
};
有关您的解决方法:
标准对这种情况说明了什么?这个代码应该编译吗?如果没有,为什么?
它不应该编译,因为事实上 C
也明确地从 A
派生出来(注意,你最终会得到两个不同的基本子对象类型 A 里面
。按照C ++ 11标准的第9.2 / 2节: C
)不会使 C
c $ c> B
类被认为是一个完全定义的对象类型 。
在类 中,<$ c $>成员规范,对于非静态数据成员(包括这样的东西),类被认为在函数体内完成,
默认参数和 brace-or-equal-initializers 在
嵌套类)。否则,在其自己的类 member-specification 内被视为不完整。
class A {
virtual A* foo() = 0;
};
template<class T>
class B : public A {
virtual T* foo() { return nullptr; }
};
class C : public B<C> {
};
This is a simplified implementation for Possibility to mix composite pattern and curiously recurring template pattern. I get the following error:
Return type of virtual function 'foo' is not covariant with the return type of the function it overrides ('C *' is not derived from 'A *')
Tested on clang 3.0, gcc 4.7 and visual studio 2008.
First solution:
class C : public A, public B<C> {}
compiles under visual studio with a warning that B is already a child of A and does not compile under clang with initial error.
Another workaround:
class D : public A {}
class C : public B<D> {}
solves the incompleteness issue, but I can't figure out how many A instances will I have. Intuition tells me that A is virtual, thus there should be only one.
Also this workaround creates unreadable code.
What does the standard states about this situation? Should this code compile? If not, why?
Your virtual function A::foo()
returns an A*
, while function B<C>::foo()
, which is meant to override it, returns a C*
.
This in theory does respect the principle of covariance, since C
is indeed a specialization of (derives from) A
, but at the point of instantiation, this is not known, because C
is an incomplete type.
One possible way to re-think your design is to make A
a class template as well, and let B
propagate the template argument for T
up to A
:
template<typename T>
class A {
virtual T* foo() = 0;
};
template<class T>
class B : public A<T> {
virtual T* foo() { return nullptr; }
};
Concerning your workaround:
What does the standard states about this situation? Should this code compile? If not, why?
It shouldn't compile, because the mere fact of making C
also derive from A
explicitly (notice, that you would end up with two distinct base sub-objects of type A
inside C
) does not make C
a complete type when instantiating B<C>
. Per Paragraph 9.2/2 of the C++11 Standard:
A class is considered a completely-defined object type (3.9) (or complete type) at the closing
}
of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.
这篇关于CRTP和动态多态编译错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!