56

根据cppreferencestd::type_info::operator!=被 C++20 删除,但是,std::type_info::operator==显然仍然存在。

背后的原因是什么?我可能同意比较不平等是没有意义的,但是比较平等也同样没有意义,不是吗?

类似地,operator!=许多其他标准库类型,包括容器,如std::unordered_map::operator!=并且std::unordered_set::operator!=将根据 cppreference 在 C++20 中删除。

与 相比,必须编写if(!(id1 == id2))不会使任何代码更清晰if(id1 != id2),相反,恰恰相反......

4

2 回答 2

69

在 C++20 中,关系运算符的工作方式发生了变化,特别是引入了 spaceship<=>运算符。特别是,如果您只提供operator==,a != b则被重写为!(a == b).

来自[over.match.oper]/3.4

改写后的候选集确定如下:

  • 对于关系 ([expr.rel]) 运算符,重写的候选包括表达式 x <=> y 的所有未重写的候选。
  • 对于关系 ([expr.rel]) 和三向比较 ([expr.spaceship]) 运算符,重写的候选还包括一个合成候选,两个参数的顺序颠倒,对于每个未重写的候选表达式 y <=> x。
  • 对于 != 运算符 ([expr.eq]),重写的候选项包括表达式 x == y 的所有未重写的候选项。
  • 对于等式运算符,重写的候选还包括一个合成的候选,两个参数的顺序颠倒,用于表达式 y == x 的每个未重写的候选。
  • 对于所有其他运算符,重写的候选集为空。

[over.match.oper]/9

如果通过重载决策为运算符 @ 选择了重写的 operator== 候选者,则其返回类型应为 cv bool,并且 x @ y 被解释为:

  • 如果 @ 是 != 并且选定的候选者是具有相反参数顺序的合成候选者,!(y == x),
  • 否则,如果 @ 是 !=, !(x == y) ,
  • 否则(当 @ 为 == 时),y == x,

在每种情况下使用选定的重写运算符== 候选。

因此,operator!=不再需要显式重载 for。删除运算符并没有改变比较语义。

据我所知,所有容器都已operator!=被移除(例如检查向量概要)。唯一的例外是容器适配器std::queuestd::stack:我的猜测是,它是为了在与第三方容器一起使用时保持向后兼容性,以防相等运算符不对称。

于 2020-02-11T21:38:23.297 回答
42

我们不再需要提供库operator!=。提供允许编译器自己operator==做一些杂耍和评估a != ba == b

[over.match.oper]

3对于具有 cv 非限定版本为 T1 的类型的操作数的一元运算符@,以及具有 cv 非限定版本为 T1 的类型的左操作数和 cv-非限定版本的类型的右操作数的二元运算符 @不合格版本为T2,四组候选函数,指定成员候选、非成员候选、内置候选和重写候选,构造如下:

3.4.3对于 != 运算符 ([expr.eq]),重写的候选者包括表达式 x == y 的所有未重写的候选者。

std::type_infooperator!=作为P1614 - The Mothership has Landed 的一部分,更多的图书馆类型已被删除。

于 2019-10-10T10:11:19.483 回答