C++20与g++13中CRTP模式下operator==重载歧义问题求助
C++20下CRTP模式中operator==的歧义问题
问题代码
#include <iostream> template <typename Type> struct PartialEq { friend bool operator==(PartialEq const&, Type const&) { return true; } }; struct A : PartialEq<A> { }; int main() { A a1{}, a2{}; std::cout << (a1 == a2) << std::endl; return 0; }
编译警告
source>: In function 'int main()': <source>:16:25: warning: C++20 says that these are ambiguous, even though the second is reversed: 16 | std::cout << (a1 == a2) << std::endl; | ^~ <source>:5:17: note: candidate 1: 'bool operator==(const PartialEq<A>&, const A&)' 5 | friend bool operator==(PartialEq const&, Type const&) { | ^~~~~~~~ <source>:5:17: note: candidate 2: 'bool operator==(const PartialEq<A>&, const A&)' (reversed)
问题原因
C++20新增了运算符对称性规则:编译器会自动为operator==生成反向调用的候选函数。在上述CRTP代码中,PartialEq<A>的友元operator==接受PartialEq<A> const&和A const&作为参数。当比较两个A对象时,存在两种等价的匹配路径:
- 将第一个
A隐式转换为PartialEq<A> const&,匹配原函数 - 将第二个
A隐式转换为PartialEq<A> const&,匹配编译器生成的反向候选
两种路径的转换成本完全相同,因此编译器判定为歧义。
解决方案
方案1:修改友元运算符参数为派生类类型
让友元operator==的两个参数均为派生类Type,这样正向和反向调用都会匹配同一个函数,消除歧义:
#include <iostream> template <typename Type> struct PartialEq { friend bool operator==(Type const& lhs, Type const& rhs) { // 可直接访问PartialEq的成员,因为Type继承自PartialEq return true; } }; struct A : PartialEq<A> { }; int main() { A a1{}, a2{}; std::cout << (a1 == a2) << std::endl; return 0; }
方案2:将运算符定义为成员函数
把operator==定义为PartialEq的成员函数,C++20会自动生成符合对称性的反向运算符,且不会产生歧义:
#include <iostream> template <typename Type> struct PartialEq { bool operator==(Type const& rhs) const { return true; } }; struct A : PartialEq<A> { }; int main() { A a1{}, a2{}; std::cout << (a1 == a2) << std::endl; std::cout << (a2 == a1) << std::endl; // 自动生成的反向运算符正常工作 return 0; }
内容的提问来源于stack exchange,提问作者nyorem
相关产品推荐
相关产品推荐

