C++17可编译的operator==代码在C++20下编译失败的兼容方案咨询
问题原因
C++20引入了比较运算符的自动重写与合成规则:只要类自定义了operator==且没有自定义operator!=,编译器会自动合成对应的operator!=,同时支持参数顺序交换的表达式重写(即a != b可被重写为!(a == b)或!(b == a))。
你的代码中a_1 != a表达式会产生3个优先级相同的候选重载,编译器无法选出最优解,因此报二义性错误:
- 重写为
!(a_1 == a),匹配A类的operator==(const A&),仅需将A_1类型的a_1转换为const A& - 重写为
!(a == a_1),同样匹配A类的operator==(const A&),仅需将A_1类型的a_1转换为const A& - 匹配全局模板
operator!=<A_1>(const T&, const Base&),仅需将A类型的a转换为const Base&
三个候选的转换序列都是派生类到基类的隐式转换,优先级完全一致,因此产生二义性。而C++17没有比较运算符合成规则,只会匹配全局模板,因此可以正常编译。
解决方案
优先选择仅修改Base类的方案,核心思路是在Base类中显式定义通用的operator!=,阻止派生类自动合成operator!=,从根源消除二义性,同时完全兼容C++17的运行逻辑。修改后的完整代码如下:
#include <stdlib.h> struct Base { // 原有全局比较逻辑移为Base的友元,保持原有语义不变 template<typename T> friend bool operator==(const T&, const Base&) { return true; } template<typename T> friend bool operator!=(const T& lhs, const Base& rhs) { return !(lhs == rhs); } // 新增通用!=重载,阻止编译器自动合成operator!= template<typename T> bool operator!=(const T&) const { // 保持和C++17版本完全一致的返回逻辑 return false; } }; struct A : public Base { bool operator==(const A&) const { return true; } }; struct A_1 final : public A { }; int main() { const A a; const A_1 a_1; if (a_1 != a) {} return EXIT_SUCCESS; }
该方案无需修改任何派生类代码,在C17和C20下均可正常编译,运行结果和原有代码完全一致。
内容的提问来源于stack exchange,提问作者Jack Brown
相关产品推荐
相关产品推荐

