自定义operator<=>为何无法配合std::ranges::sort使用?
这完全符合C++20及后续版本的标准规则,并非编译器缺陷,原因如下:
核心差异:std::ranges::less与std::less的约束不同
std::ranges::sort默认使用std::ranges::less作为比较器,而std::ranges::less的operator()有严格的模板概念约束:它要求参与比较的类型满足std::totally_ordered_with概念。
std::totally_ordered_with依赖两个关键子概念:
std::equality_comparable:要求类型存在合法的operator==,且满足等价关系的公理(自反、对称、传递)。std::three_way_comparable:要求类型存在operator<=>,且能产生合法的强序/弱序结果。
为什么自定义operator<=>会触发错误?
C++20标准明确规定:只有当operator<=>被声明为=default时,编译器才会自动生成对应的operator==。如果是手动实现的自定义operator<=>,编译器不会自动生成operator==。此时:
- 结构体
A不满足std::equality_comparable概念,进而导致std::totally_ordered_with不成立。 std::ranges::less的operator()因模板约束不满足而无法调用,最终触发std::invocable_v<std::ranges::less&,A&,A&>不成立的错误。
三个观察点的原因解析
std::sort可正常运行:
传统std::sort使用的是std::less,它没有基于概念的严格约束,仅尝试调用operator<(而operator<可由自定义operator<=>自动生成),只要运行时行为符合严格弱序即可,不会在编译期强制检查equality_comparable。添加自定义
operator==后正常:
手动添加operator==后,结构体A满足std::equality_comparable概念,std::totally_ordered_with约束被满足,std::ranges::less的operator()可以正常调用。默认
=default的operator<=>可正常运行:
使用=default的operator<=>时,编译器会自动生成匹配的operator==,结构体A自然满足std::equality_comparable和std::totally_ordered_with概念,符合std::ranges::less的约束要求。
补充疑问:为什么std::ranges::less需要operator==?
并非std::ranges::less直接需要operator==,而是它依赖的std::totally_ordered_with概念要求类型满足全序关系——全序关系不仅需要可比较大小,还需要可判定等价性(即两个元素既不小于也不大于彼此的情况下,视为等价)。std::equality_comparable概念确保了等价性的合法判定,这是全序关系的必要组成部分,也是std::ranges::sort依赖严格弱序进行正确排序的基础。
内容的提问来源于stack exchange,提问作者PiotrNycz

