基类非同类参数operator==致带spaceship运算符的子类实例化失败是GCC bug吗
问题复现
你遇到的编译问题可通过如下最小代码复现:
#include <compare> struct A { std::strong_ordering operator<=>(const A &) const = default; bool operator==(int) const; }; struct B : A { virtual std::strong_ordering operator<=>(const B &) const noexcept = default; }; B b; // GCC编译在此处报错
报错核心提示为B::operator==被隐式删除,找不到匹配的基类A的相等运算符。
结论
这不是GCC的bug,该编译行为完全符合C++标准要求。
规则依据与错误原因
- C++20标准规定:当类显式默认声明
operator<=>且没有用户自定义的同签名operator==时,编译器会隐式生成逐成员、逐基类比较的默认operator==。 - 基类
A由于用户自行声明了参数为int的operator==重载,只要类中存在任何用户声明的operator==,无论参数类型是什么,编译器都不会再为A隐式生成默认的operator==(const A&) const。 - 子类
B默认声明了虚函数operator<=>,对应隐式生成的operator==也为虚函数,它的默认实现需要比较两个A类型的基类子对象,但是找不到匹配的A的相等运算符,因此B::operator==被隐式标记为删除。 - 带有虚函数的类实例化时,编译器需要生成虚函数表,虚表会引用所有声明的虚函数,包括这个被删除的
B::operator==,因此实例化B对象时直接触发编译错误。
修复方案
你可以选择任意一种方式修复该问题:
- 给基类
A补充默认的相等运算符:bool operator==(const A&) const = default; - 去掉
B::operator<=>的virtual修饰符,只要不主动调用B的相等比较,实例化不会报错 - 自行定义
B::operator==(const B&) const的实现,不需要依赖编译器隐式生成
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

