59

C++20 中有一个新的比较运算符<=>。但是我认为在大多数情况下,简单的减法效果很好:

int my_strcmp(const char *a, const char *b) {
    while (*a == *b && *a != 0 && *b != 0) {
        a++, b++;
    }
    // Version 1
    return *a - *b;
    // Version 2
    return *a <=> *b;
    // Version 3
    return ((*a > *b) - (*a < *b));
}

它们具有相同的效果。我真的无法理解其中的区别。

4

3 回答 3

59

运算符通过减法解决了数字溢出问题:如果从接近 的负数中减去一个大的正数INT_MIN,则会得到一个无法表示为 的数字int,从而导致未定义的行为。

虽然版本 3 没有这个问题,但它完全缺乏可读性:以前从未见过这个技巧的人需要一些时间才能理解。<=>运算符也修复了可读性问题。

这只是新运营商解决的一个问题。Herb Sutter 的一致比较论文的第 2.2.3 节讨论了<=>与语言的其他数据类型一起使用,其中减法可能会产生不一致的结果。

于 2017-12-31T13:46:18.517 回答
43

以下是一些减法不起作用的情况:

  1. unsigned类型。
  2. 导致整数溢出的操作数。
  3. 未定义的用户定义类型operator -(可能是因为它没有意义 - 可以定义顺序而不定义距离概念)。

我怀疑这个列表并不详尽。

当然,至少可以为#1 和#2 提出解决方法。但目的operator <=>是封装这种丑陋。

于 2017-12-31T13:46:07.907 回答
18

这里有一些关于差异的有意义的答案,但 Herb Sutter 在他的论文中特别指出:

<=> 适用于类型实现者:操作符<=> 实现之外的用户代码(包括通用代码)几乎不应该直接调用 <=> (正如在其他语言中已经发现的一种良好做法);

所以即使没有区别,操作符的意义也不同:帮助类编写者生成比较操作符。

减法运算符和“宇宙飞船”运算符之间的核心区别(根据 Sutter 的提议)是重载operator-为您提供减法运算符,而重载operator<=>

  • 为您提供 6 个核心比较运算符(即使您将运算符声明为default:无需编写代码!);
  • 声明您的类是否具有可比性、可排序性以及顺序是完全的还是部分的(Sutter 提议中的强/弱);
  • 允许异类比较:您可以重载它以将您的类与任何其他类型进行比较。

其他区别在于返回值:operator<=>将返回enum一个类,该类指定该类型是否可排序以及排序是强排序还是弱排序。返回值将转换为 -1、0 或 1(尽管 Sutter 为返回类型留出了空间来指示距离,就像strcmp这样做一样)。无论如何,假设返回值为 -1, 0, 1,我们最终将在 C++ 中得到一个真正的符号函数!( signum(x) == x<=>0)

于 2017-12-31T16:44:40.083 回答