【问题标题】:How is the three-way comparison operator different from subtraction?三向比较运算符与减法有何不同?
【发布时间】:2018-06-11 02:17:58
【问题描述】:

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

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

【问题讨论】:

  • 整数减法是执行三向比较的老方法,但它可能会溢出。它也不适用于无符号类型总是。另一种方法是 ((*a > *b) - (*a
  • 甚至有人谈到允许任何具有默认 &lt;=&gt; 的类型作为非类型模板参数。该运算符的后果不仅仅是替代仅对算术类型“有效”的一种运算。
  • @iBug:那么……对于不是字符数组的事物进行三向比较,你到底打算做什么?
  • 正如您所说,在大多数情况下,简单的减法效果很好。其他情况呢?
  • @wvxvw 你是说(2 ** (sizeof(char) * CHAR_BIT))吗?

标签: c++ comparison-operators c++20 spaceship-operator


【解决方案1】:

这里有一些关于差异的有意义的答案,但 his paper 中的 Herb Sutter 明确表示:

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

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

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

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

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

【讨论】:

    【解决方案2】:

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

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

    这只是新操作员解决的一个问题。 Herb Sutter's Consistent comparison paper 的第 2.2.3 节讨论了将 &lt;=&gt; 与语言的其他数据类型一起使用,其中减法可能会产生不一致的结果。

    【讨论】:

    • 你能解释一下理解第三版的技巧吗?在我看来(假/真 - 真/假)
    • @asgs 这个技巧利用了 C/C++ 中布尔值的“对偶性”,其中比较运算符返回的 truefalse 值实际上分别是整数 10This Q&A 提供了有关此技巧的更多详细信息。
    【解决方案3】:

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

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

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

    当然,至少可以为#1 和#2 想出解决方法。但operator &lt;=&gt; 的意图是封装这种丑陋。

    【讨论】:

    • 请注意,对字符串(不仅仅是const char*,而是一个实际的字符串类)进行三向比较是一种合理的操作。减去两个字符串不是。
    猜你喜欢
    • 2021-06-14
    • 2021-11-07
    • 2021-07-20
    • 2019-03-27
    • 2020-06-26
    • 2010-09-09
    相关资源
    最近更新 更多