为何C++20中重载<=>仍需额外重载==以支持所有比较运算符?
你手动实现operator<=>后发现编译器没有自动生成operator==,这是C++20标准的明确规定,核心原因在于手动实现的三路比较运算符和默认生成的三路比较运算符,在编译器的处理逻辑上完全不同:
默认<=>的特殊待遇
当你用=default声明operator<=>时,编译器会同时自动生成operator==,因为默认的三路比较是基于成员的逐值比较,相等性和排序逻辑是统一的,编译器可以安全推导两者的等价关系。手动<=>的独立性
一旦你手动实现operator<=>,编译器会认为你是在自定义排序逻辑——这种逻辑可能和相等性判断的语义不一致。比如有些场景下,排序时会忽略某些成员(比如对象的元数据),但相等性判断需要严格匹配所有成员;或者手动实现的<=>里的equal分支只是排序等价,而非逻辑上的完全相等。编译器无法假设你的手动<=>逻辑能直接等价于==的需求,因此不会自动生成operator==。
根据C++20的规则,只要你同时提供了手动实现的operator<=>和operator==,编译器就会自动合成剩下的所有比较运算符(<、<=、>、>=),这也是你看到的指南里提到的逻辑:
在C++20中,如果未直接实现某一比较运算符,编译器会尝试使用重写候选。因此即使<=>未被默认(默认会实现所有运算符),我们也只需实现==和<=>,其余比较运算符会基于这两者重写。
举你的代码为例:
你实现的三路比较:
friend auto operator<=>(const Some_class& lhs, const Some_class& rhs) { if (lhs.x < rhs.x) return std::strong_ordering::less; if (lhs.x > rhs.x) return std::strong_ordering::greater; else return std::strong_ordering::equal; }
这段代码里的equal分支确实和==逻辑一致,但编译器不会主动复用这个逻辑,必须你手动补充operator==:
friend bool operator==(const Some_class& lhs, const Some_class& rhs) { return lhs.x == rhs.x; }
内容的提问来源于stack exchange,提问作者a_floating_point

