CRTP and dynamic polymorphism compile error

杀马特。学长 韩版系。学妹 提交于 2019-11-30 04:55:13

问题


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?


回答1:


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.



来源:https://stackoverflow.com/questions/15570333/crtp-and-dynamic-polymorphism-compile-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!