三向比较运算符与减法有何不同?

How is the three-way comparison operator different from subtraction?

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));
}

它们的作用是一样的。我真的无法理解其中的区别。

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

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

我怀疑这份清单并不详尽。

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

该运算符解决了减法时出现的数值溢出问题:如果从接近 INT_MIN 的负数中减去一个较大的正数,您将得到一个无法表示为 int,从而导致未定义的行为。

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

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

这里有一些关于差异的有意义的答案,但是 his paper 中的 Herb Sutter 特别指出:

<=> is for type implementers: User code (including generic code) outside the implementation of an operator<=> should almost never invoke an <=> directly (as already discovered as a good practice in other languages);

所以即使没有区别,运算符的意义也不同:帮助 class 作者生成比较运算符。

减法运算符和 "spaceship" 运算符的核心区别(根据 Sutter 的提议)是重载 operator- 给你一个减法运算符,而重载 operator<=>:

  • 给你6个核心比较运算符(即使你把运算符声明为default:没有代码可写!);
  • 声明你的class是否具有可比性,是否可排序,以及顺序是全部还是部分(strong/weak在Sutter的提案中);
  • 允许异构比较:您可以重载它以将您的 class 与任何其他类型进行比较。

其他区别在于 return 值:operator<=> 会 return 一个 class 的 enum,class 指定是否类型是可排序的,排序是强还是弱。 return 值将转换为 -1、0 或 1(尽管 Sutter 为 return 类型留出了空间以指示距离,就像 strcmp 那样)。无论如何,假设 -1, 0, 1 return 值,我们最终会得到 a true signum function in C++! (signum(x) == x<=>0)