协变返回类型,常量和不完整的类

时间:2016-07-22 19:08:35

标签: c++ covariance

此代码在g ++ 6.1下成功编译,但在clang 3.8中出错:

class C;

class Base {
public:
  virtual const C *getC();
};

class Derived : public Base {
public:
  virtual       C *getC();
};

clang的错误如下:

$ dev/compilers/linux-x86_64-2.12.2/clang3.8/bin/clang++ -Wall -c testcovariantreturn.cxx
testcovariantreturn.cxx:10:20: error: return type of virtual function 'getC' is not covariant with the return type of the function it overrides ('C' is incomplete)

如果完全定义了C类而不是前向声明,则没有错误。我的理解是,当覆盖虚方法时,协变允许“较小”的cv资格(即,从返回类型中删除const)。

clang是否正确/允许需要完整类型,如果是,为什么?如何让C的定义在这里改变什么?

这不是完全学术性的,在大型代码库中我不愿意添加不必要的包含,我们尝试将声明转发为标准实践。

2 个答案:

答案 0 :(得分:17)

这是clang 3.8 bug,特别是26297。来自[class.virtual],来自N4594的措辞:

  

重写函数的返回类型应与重写函数的返回类型相同   或协变与函数的类。如果函数D::f覆盖函数B::f,则返回类型   如果满足以下条件,则函数是协变的:   (7.1) - 两者都是指向类的指针,都是对类的左值引用,或者两者都是对它们的右值引用   班
  (7.2) - 返回类型B::f中的类与返回类型D::f中的类相同,或者是   返回类型为D::f的类的明确且可访问的直接或间接基类   (7.3) - 指针或引用在D::f的返回类型中具有相同的cv-qualification和类类型   与B::f的返回类型中的类类型具有相同的cv资格或更少的cv资格。

B::f返回C const*D::f返回C*符合所有这些要求(指针都不是cv限定的,类类型为D::f比基数更少cv认证,因此应该允许。

没有要求完整性; C不需要完整来检查这些标准。

答案 1 :(得分:3)

我也发现你的代码没有问题。它编译了clang的头版和我尝试过的所有编译器,除了clang 3.8和更早版本。

Live demo

相关标准文本:

  

10.3注8:

     

如果D :: f的协变返回类型中的类类型不同   B :: f的那个,D :: f的返回类型中的类类型应该是   完成在D :: f 的声明点或应该是类   输入D.

协变方法的类类型必须相同或 完成,但据我了解,仍然考虑const / volatile的差异  相同的类类型,使您的示例合法。