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

iBu*_*Bug 51 c++ comparison-operators spaceship-operator c++20

<=>在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));
}
Run Code Online (Sandbox Code Playgroud)

它们具有相同的效果.我无法理解其中的差异.

das*_*ght 53

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

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

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

  • @asgs这个技巧在C/C++中利用了布尔运算的"二元性",比较运算符返回的"true"和"false"值实际上分别是整数"1"和"0".[此问答](/sf/answers/322685681/)提供了有关此技巧的更多详细信息. (8认同)

Oli*_*rth 40

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

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

我怀疑这份清单并非详尽无遗.

当然,至少可以为#1和#2提供变通方法.但其意图operator <=>是将这种丑陋所包含在内.

  • 请注意,对字符串进行3向比较(不仅仅是`const char*`而是实际的字符串类)是一种合理的操作.减去两个字符串不是. (16认同)

Cri*_*ngo 16

这里有一些有意义的答案,但Herb Sutter在他的论文中特别说:

<=>是类型实施者:操作的执行之外的用户代码(包括通用代码)<=>应该几乎从不调用<=>直接(如已发现在其他语言中一个很好的做法);

因此,即使没有区别,运算符的要点也不同:帮助类编写者生成比较运算符.

减法运算符和"太空飞船"运算符之间的核心差异(根据Sutter的提议)是重载operator-为您提供减法运算符,而重载operator<=>:

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

其他差异在于返回值:operator<=>将返回enum一个类,该类指定该类型是否可排序以及排序是强还是弱.返回值将转换为-1,0或1(尽管Sutter为返回类型留出空间以指示距离,同样strcmp如此).在任何情况下,假设返回值为-1,0,1,我们最终将在C++中获得真正的signum函数!(signum(x) == x<=>0)