【问题标题】:Overriding spaceship operator when parent class does not define spaceship operator for itself当父类没有为自己定义飞船运算符时覆盖飞船运算符
【发布时间】:2022-01-16 22:21:54
【问题描述】:

编译器对以下代码的处理方式不同:

#include <compare>

struct A;

struct I {
    virtual std::strong_ordering operator <=>(const A&) const { 
        return std::strong_ordering::equal; 
    }
};

struct A : I {
    virtual std::strong_ordering operator <=>(const A&) const = default;
};

GCC 和 MSVC 都接受它,但 Clang 不接受它返回错误:

warning: explicitly defaulted three-way comparison operator is implicitly deleted [-Wdefaulted-function-deleted]
    virtual std::strong_ordering operator <=>(const A&) const = default;
defaulted 'operator<=>' is implicitly deleted because there is no viable three-way comparison function for base class 'I'
error: deleted function 'operator<=>' cannot override a non-deleted function
    virtual std::strong_ordering operator <=>(const A&) const = default;

演示:https://gcc.godbolt.org/z/WGrGTe89z

这里好像只有Clang,因为I::operator &lt;=&gt;(const I&amp;) const没有定义,所以A::operator &lt;=&gt;(const A&amp;) const必须被隐式删除,一个deleted的方法不能覆盖I的一个notdeleted的方法。其他编译器是否也有权接受代码?

【问题讨论】:

  • 虚拟比较算子是个雷区

标签: c++ overriding language-lawyer spaceship-operator


【解决方案1】:

一旦您编写了A a; a &lt; a; 之类的代码,其他编译器也会拒绝该代码,这让我认为 Clang 过早地拒绝了它。在[class.compare.default],标准说:

类 C 的比较运算符函数在其第一次声明时默认且未定义为已删除,当它被使用或需要用于常量评估时,它会被隐式定义。 比较运算符函数的默认定义中的名称查找是从与其函数体等效的上下文中执行的。 出现在类中的默认比较运算符的定义应是该函数的第一个声明。

由于在您的示例中没有解析为 A::operator&lt;=&gt;(const A&amp;) 的表达式,因此不需要定义并且不应拒绝它,即使函数最终会被删除。

【讨论】:

  • 谢谢。事实上,其他编译器也隐式删除了A::operator &lt;=&gt;(const A&amp;) const,但这应该是一个编译错误,因为具有这种签名的方法是基类中的虚拟方法,不能在子类中删除。这会导致其他编译器在链接时 (GCC) 错误地失败或生成无效代码 (MSVC),演示:gcc.godbolt.org/z/cfsa3ncq6
  • @Fedor:三种不同的结果!真是一团糟。那个演示代码很臭,我可以看到 Clang 想让你不要上吊。但是,我不认为(i &lt;=&gt; a) 是 odr-using A::operator&lt;=&gt;(const A&amp;),所以标准可能不需要对这种不正当行为发出警告。
猜你喜欢
  • 2011-03-04
  • 1970-01-01
  • 2010-10-24
  • 2021-08-07
  • 1970-01-01
  • 2015-06-10
  • 2020-09-28
  • 2010-11-25
相关资源
最近更新 更多