此代码在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的定义在这里改变什么?
这不是完全学术性的,在大型代码库中我不愿意添加不必要的包含,我们尝试将声明转发为标准实践。
答案 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和更早版本。
相关标准文本:
10.3注8:
如果D :: f的协变返回类型中的类类型不同 B :: f的那个,D :: f的返回类型中的类类型应该是 完成在D :: f 的声明点或应该是类 输入D.
协变方法的类类型必须相同或 完成,但据我了解,仍然考虑const / volatile的差异 相同的类类型,使您的示例合法。