为何std::equality_comparable_with在已正确定义==运算符的简单场景下不生效?
为何std::equality_comparable_with在已正确定义==运算符的简单场景下不生效?
这个问题我刚接触C++20概念的时候也踩过一模一样的坑!当时我也纳闷:明明双向的==都定义好了,怎么标准库的概念反而不通过?
其实核心原因是**std::equality_comparable_with的设计目标远不止“能编译双向==”这么简单**,它是为了规范符合等价关系的跨类型比较,而不是仅仅检查运算符是否存在。我们来拆解它的要求:
- 首先它确实要求
a == b和b == a都能编译,且返回值可转换为bool; - 但它还额外要求:
- 存在
std::common_reference_t<const A&, const B&>(也就是A和B的公共引用类型),或者更准确地说,满足std::common_reference_with<const A&, const B&>概念; - 这个公共类型本身必须满足
std::equality_comparable; a == b的结果必须等价于“把a和b都转换成公共类型后再比较相等”,反过来b == a也要满足这个等价性。
- 存在
那为什么要加公共类型的要求呢?这是因为标准库希望这个概念描述的是语义上等价的跨类型比较,比如int和long的比较:它们有公共类型long,转换后比较的结果和直接比较一致,而且这种比较满足等价关系的传递性(比如int(5) == long(5),long(5) == int(5),同时int(5) == int(5)也成立)。
而你定义的A和B是完全无关的类型,没有默认的公共类型,即使你写了==运算符,标准库也无法保证这种比较符合它期望的等价语义——比如没法保证a == b、b == a和公共类型的比较之间的一致性,所以std::equality_comparable_with就不通过。
反观你自己写的IsEqualityComparable概念,它只检查了双向==的存在和返回类型,这是一个更宽松的检查,所以自然能通过。
如果想要让std::equality_comparable_with<A,B>通过,你有两个选择:
- 给
A和B定义公共类型:比如让其中一个可以隐式转换到另一个,或者特化std::common_reference模板来指定它们的公共类型; - 如果你只是需要检查双向
==是否存在,那继续用你自己的IsEqualityComparable概念就好,std::equality_comparable_with本来就不是为这种场景设计的。
内容来源于stack exchange
相关产品推荐
相关产品推荐

