代码之家  ›  专栏  ›  技术社区  ›  iBug

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

  •  60
  • iBug  · 技术社区  · 7 年前

    有一个新的比较运算符 <=> 在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));
    }
    

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

    3 回复  |  直到 7 年前
        1
  •  59
  •   Sergey Kalinichenko    7 年前

    运算符解决了减法运算中出现的数字溢出问题:如果从接近 INT_MIN ,您得到的数字不能表示为 int ,从而导致未定义的行为。

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

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

        2
  •  43
  •   Oliver Charlesworth    7 年前

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

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

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

    当然,至少可以为#1和#2找到解决方法。但是 operator <=> 就是把那丑陋的东西封装起来。

        3
  •  18
  •   Cris Luengo    7 年前

    关于这一差异,这里有一些有意义的答案,但赫伯·萨特 his paper 特别指出:

    <=>用于类型实现者:运算符实现之外的用户代码(包括泛型代码)<=&燃气轮机;几乎不应调用<=&燃气轮机;直接(在其他语言中已经发现这是一种很好的做法);

    因此,即使没有差异,操作符的意义也不同:帮助类编写器生成比较操作符。

    减法运算符和“太空船”运算符(根据萨特的建议)之间的核心区别在于重载 operator- 为您提供一个减法运算符,而重载 operator<=> :

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

    其他差异在于返回值: 操作员(<)=&燃气轮机; 将返回 enum 对于类,该类指定类型是否可排序以及排序是强排序还是弱排序。返回值将转换为-1、0或1(尽管Sutter为返回类型留出了空间,以指示距离,如 strcmp 是的)。在任何情况下,假设返回值为-1,0,1,我们最终将得到 a true signum function in C++ ! ( signum(x) == x<=>0 )