CRTP和动态多态编译错误 [英] CRTP and dynamic polymorphism compile error

查看:96
本文介绍了CRTP和动态多态编译错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  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 :: foo()它返回一个 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 )不会使 C c $ c> B 。按照C ++ 11标准的第9.2 / 2节:


类被认为是一个完全定义的对象类型
在类 中,<$ 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆