协变返回类型、常量和不完整类
Posted
技术标签:
【中文标题】协变返回类型、常量和不完整类【英文标题】:Covariant return types, const-ness, and incomplete classes 【发布时间】:2016-07-22 19:08:35 【问题描述】:此代码在 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 的定义可用如何改变这里的任何东西?
这并不完全是学术性的,在大型代码库中我不愿意添加不必要的包含,我们尝试将声明作为标准做法。
【问题讨论】:
此代码是协变的,因此理想情况下它应该被接受。相反的const
方差不会是协变的,并且会支持原始const
对象的UB 修改。这就是说(这很重要)我不知道 C++ 标准对此有什么看法,如果有的话。
【参考方案1】:
这是 clang 3.8 的错误,特别是 26297。来自 [class.virtual],来自 N4594 的措辞:
重写函数的返回类型应与重写函数的返回类型相同 或 协变 与函数的类。如果函数
D::f
覆盖函数B::f
,则返回类型 如果满足以下条件,则这些函数是协变的: (7.1) — 都是指向类的指针,都是指向类的左值引用,或者都是指向类的右值引用 课程 (7.2)——B::f
返回类型中的类与D::f
返回类型中的类是同一个类,或者是D::f
返回类型中类的明确且可访问的直接或间接基类 (7.3) — 指针或引用都具有相同的 cv 限定和D::f
返回类型中的类类型 与B::f
的返回类型中的类类型具有相同或更少的cv-qualification。
具有B::f
return C const*
和 D::f
return C*
符合所有这些要求(指针都不是 cv 限定的,D::f
的类类型比基类更少 cv 限定),因此应该允许。
对完整性没有要求; C
不需要完整即可检查这些标准。
【讨论】:
哦,我应该在评论之前阅读您的回答。所以现在我也知道标准是怎么说的了。赞成。 :) 能否请您提及您引用的标准或草案,因为详细的措辞会随着时间的推移而变化。谢谢。 @Cheersandhth.-Alf 当然。这部分并没有真正改变。 2005 年草案的措辞基本相同(关于右值引用的模数措辞)。 我能找到的唯一半相关的 clang 错误是 llvm.org/bugs/show_bug.cgi?id=17859 这实际上与我的问题相反——它声称 clang 允许删除非类返回类型的 const... @ChrisMorley 这是llvm.org/bugs/show_bug.cgi?id=26297,已添加到答案中。【参考方案2】:我也发现您的代码没有任何问题。它可以使用 clang 的 head 版本和我尝试过的所有编译器进行编译,除了 clang 3.8 和更早版本。
Live demo
相关标准文本:
10.3 注释 8:
如果 D::f 的协变返回类型中的类类型不同于 B::f 的返回类型中的类类型应为 完成在 D::f 的声明点 or 应该是类 D型。
协变方法的类类型必须相同或 完整,但据我了解,仍会考虑 const/volatile 差异 相同的类类型,使您的示例合法。
【讨论】:
const
差异对协方差很重要。如果覆盖将const
添加到指针对象,则它可以在类型系统中(无强制转换)返回指向最初const
对象的指针。然后,使用基类虚函数的客户端代码代码可以尝试修改原来的 const
对象,= UB。
我不确定这里是否支持 C++ 标准,但无论标准的措辞如何,它都非常重要。 :)
@Cheersandhth.-Alf,这很重要,但我想特别提到的是当 incomplete 类型被允许时的措辞。
我在上面发布 cmets 时不知道,但Barry's answer 引用了其中一个 C++ 标准,因此现在很明显这个答案是错误的(就其含义而言) .
谢谢,演示工具不错以上是关于协变返回类型、常量和不完整类的主要内容,如果未能解决你的问题,请参考以下文章