什么是C++中的<=>运算符?

q-l*_*l-p 200 c++ operators c++-faq spaceship-operator c++20

当我试图了解C++运算符时,我偶然发现cppreference.com上的一个奇怪的比较运算符,*在一个如下所示的表中:

在此输入图像描述

"好吧,如果这些是C++中常见的操作符,我会更好地学习它们",我想.但我所有试图阐明这个谜团的尝试都没有成功.即使在这里,在Stack Overflow上我的搜索也没有运气.

<=>C++之间是否存在联系?

如果有的话,这个运营商到底做了什么?

*与此同时,cppreference.com更新了该页面,现在包含有关<=>运营商的信息.

msc*_*msc 170

这称为三向比较运算符.

根据P0515文件提案:

有一个新的三向比较运算符,<=>.表达式a <=> b返回一个对象,该对象比较<0if a < b,compare >0if a > b和compare ==0if ab等于/等效.

要为您的类型编写所有比较,只需写入operator<=>返回适当的类别类型:

  • 返回的_ordering如果你的类型自然地支持<,我们将有效地产生<,>,<=,>=,==,和!=; 否则返回_equality,我们将有效地生成 ==!=.

  • 如果您的类型a == b暗示f(a) == f(b)(可替换性,其中f只读取比较 - 使用非私有const接口可访问的显着状态),则返回强,否则返回弱.

cppreference说:

三向比较运算符表达式具有形式

lhs <=> rhs   (1)  
Run Code Online (Sandbox Code Playgroud)

表达式返回一个对象

  • 比较<0如果lhs < rhs
  • 比较>0如果lhs > rhs
  • 并比较==0if lhsrhs是否相等/等价.

  • 对于那些对"比较`<0`","比较`> 0""和"比较'== 0`"的人感到困惑的人,他们的意思是,`<=>`返回负数,正值或零值,取决于参数.就像`strncmp`和`memcmp`. (88认同)
  • “强势回归”和“弱势回归”是什么意思? (3认同)
  • @hkBattousai 这意味着对象返回,当比较 `&lt; 0` 评估为真。也就是说,如果`a &lt; b` 那么`(a &lt;=&gt; b) &lt; 0` 总是为真。 (2认同)

q-l*_*l-p 110

2017-11-11,ISO C++委员会采用了 Herb Sutter关于<=>"太空船"三向比较运算符的提议,作为添加到C++ 20中的新功能之一.在题为Consistent comparison Sutter 的文章中,Maurer和Brown展示了新设计的概念.有关该提案的概述,以下是该文章的摘录:

表达式a <=> b返回一个对象,如果a <b则比较<0,如果> b则比较> 0,如果a和b等于/等于,则比较== 0.

常见情况:要使用类型Y为类型X编写所有比较,使用成员语义,只需写:

auto X::operator<=>(const Y&) =default;
Run Code Online (Sandbox Code Playgroud)

晚期病例:要写出你的类型所有比较XŸ,只写操作<=>,需要一个Ÿ,可以使用 =默认获取如果需要按成员的语义,并返回相应的类别类型:

  • 如果你的类型自然支持<,则返回_ordering,我们将有效地生成对称<,>,<=,> =,==!= ; 否则返回_equality,我们将有效地生成对称==!=.
  • 返回strong_如果你的类型a == b暗示f(a)== f(b)(可替代性,其中f只读取使用公共const成员可访问的比较显着状态),否则返回 weak_.

比较类别

五个比较类别被定义为std::类型,每个类型具有以下预定义值:

+--------------------------------------------------------------------+
|                  |          Numeric  values          | Non-numeric |
|     Category     +-----------------------------------+             |
|                  | -1   | 0          | +1            |   values    |
+------------------+------+------------+---------------+-------------+
| strong_ordering  | less | equal      | greater       |             |
| weak_ordering    | less | equivalent | greater       |             |
| partial_ordering | less | equivalent | greater       | unordered   |
| strong_equality  |      | equal      | nonequal      |             |
| weak_equality    |      | equivalent | nonequivalent |             |
+------------------+------+------------+---------------+-------------+
Run Code Online (Sandbox Code Playgroud)

这些类型之间的隐式转换定义如下:

  • strong_ordering与值{ less,equal,greater}隐式转换为:
    • weak_ordering用值{ less,equivalent,greater}
    • partial_ordering用值{ less,equivalent,greater}
    • strong_equality用值{ unequal,equal,unequal}
    • weak_equality用值{ nonequivalent,equivalent,nonequivalent}
  • weak_ordering与值{ less,equivalent,greater}隐式转换为:
    • partial_ordering用值{ less,equivalent,greater}
    • weak_equality用值{ nonequivalent,equivalent,nonequivalent}
  • partial_ordering与值{ less,equivalent,greater,unordered}隐式转换为:
    • weak_equality用值{ nonequivalent,equivalent,nonequivalent,nonequivalent}
  • strong_equality值{ equal,unequal}隐式转换为:
    • weak_equality值{ equivalent,nonequivalent}

三方比较

<=>令牌介绍.旧源代码中的字符序列<=>标记为<= >.例如,X<&Y::operator<=>需要添加一个空格来保留其含义.

可重载运算符<=>是一种三向比较函数,其优先级高于<和低于<<.它返回一个可以与文字进行比较的类型,0但允许其他返回类型,例如支持表达式模板.<=>在语言和标准库中定义的所有运算符都返回上述5 std::种比较类别类型中的一种.

对于语言类型,提供了以下内置的<=>相同类型比较.除非另有说明,否则所有都是constexpr.使用标量促销/转换不能异步调用这些比较.

  • 对于bool,整数和指针类型,<=>返回strong_ordering.
  • 对于指针类型,允许不同的cv-qualifications和derived-to-base转换调用同构内置<=>,并且内置异构operator<=>(T*, nullptr_t).只有指向同一对象/分配的指针的比较才是常量表达式.
  • 对于基本浮点类型,<=>返回partial_ordering,并且可以通过将参数扩展为更大的浮点类型来异步调用.
  • 对于枚举,<=>返回与枚举的基础类型相同<=>.
  • 对于nullptr_t,<=>回报strong_ordering和总是收益equal.
  • 对于可复制数组,T[N] <=> T[N]返回与Ts 相同的类型<=>并执行字典元素比较.<=>其他阵列没有.
  • 因为void没有<=>.

为了更好地理解该操作员的内部工作原理,请阅读原始论文.这正是我发现使用搜索引擎的原因.

  • @Leandro宇宙飞船的操作者就是那个比较方法。此外,它可以正常工作并写入(或删除)其他六个比较运算符。我将采用一个比较运算符函数,该函数将写在六个单独的样板上。 (5认同)
  • 请注意,`_equality` 类型已失效:事实证明,`&lt;=&gt;` 与四个关系运算符配合得很好,但与两个相等运算符配合得不好(尽管有一些强大的语法糖来支持您想要所有内容的常见情况)其中)。 (4认同)
  • 好像 cpp 还不够复杂。为什么不简单地写一个比较方法...... (3认同)

小智 23

C++ 20 中引入了三向比较运算符 (<=>)。

该表达式返回如下对象;

auto cmp  = a <=> b;

cmp > 0 if a > b
cmp = 0 if a == b
cmp < 0 if a < b  
Run Code Online (Sandbox Code Playgroud)

示例程序

#include <iostream>

using namespace std;

int main()
{
        int lhs = 10, rhs = 20;
        auto result = lhs <=> rhs;

        if (result < 0) {
                cout << "lhs is less than rhs" << endl;
        }
        else if (result > 0) {
                cout << "lhs is greater than rhs" << endl;
        }
        else {
                cout << "lhs and rhs are equal" << endl;
        }

}
Run Code Online (Sandbox Code Playgroud)

如何编译并运行?

g++-10 threewaycmp.cpp -std=c++20
./a.out
Run Code Online (Sandbox Code Playgroud)

结果

lhs is less than rhs
Run Code Online (Sandbox Code Playgroud)

请参阅以下链接了解更多详细信息 https://en.cppreference.com/w/cpp/language/operator_comparison


Sti*_*mer 11

由于引用的网页已更改,因此此答案变得无关紧要

您引用网页已损坏.那天正在编辑很多,不同的部分不同步.我在看它时的状态是:

在页面顶部,它列出了当前存在的比较运算符(在C++ 14中).没有<=>.

在页面的底部,他们应该列出相同的运营商,但他们蠢蠢欲动,并添加了这个未来的建议.

gcc还不知道<=>(并且-std=c++14,从不会),所以它认为你的意思a <= > b.这是解释错误消息.

如果你从现在起五年后尝试同样的事情,你可能会收到更好的错误信息,例如 <=> not part of C++14.

  • 我打算链接到与问题相同的网页,但错过了.我想我回答了其他答案没有的部分问题.我忽略了主要粗体问题,因为其他人已经回答了这个问题. (2认同)

Cir*_*四事件 7

默认<=>自动==, !=, <, >, <=, >=免费提供

C++20 有一个新的“默认比较”功能设置,因此默认设置<=>免费提供所有其他功能。我相信这是添加operator<=>.

改编自https://en.cppreference.com/w/cpp/language/default_comparisons

主程序

#include <cassert>
#include <compare>
#include <set>

struct Point {
    int x;
    int y;
    auto operator<=>(const Point&) const = default;
};

int main() {
    Point pt1{1, 1}, pt2{1, 2};

    // Just to show it Is enough for `std::set`.
    std::set<Point> s;
    s.insert(pt1);

    // All of these are automatically defined for us!
    assert(!(pt1 == pt2));
    assert( (pt1 != pt2));
    assert( (pt1 <  pt2));
    assert( (pt1 <= pt2));
    assert(!(pt1 >  pt2));
    assert(!(pt1 >= pt2));
}
Run Code Online (Sandbox Code Playgroud)

编译并运行:

sudo apt install g++-10
g++-10 -ggdb3 -O0 -std=c++20 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
Run Code Online (Sandbox Code Playgroud)

上面的一个等效的更明确的版本是:

struct Point {
    int x;
    int y;
    auto operator<=>(const Point& other) const {
        if (x < other.x) return -1;
        if (x > other.x) return 1;
        if (y < other.y) return -1;
        if (y > other.y) return 1;
        return 0;
    }
    bool operator==(const Point& other) const = default;
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我们需要显式设置,bool operator==(const Point& other) const = default;因为如果operator<=>没有默认(例如上面明确给出),则operator==不会自动默认:

每对任何规则的operator<=>过载,一个默认的<=>超载也将允许类型进行比较了<<=>,和>=

如果operator<=>是默认值并且operator==根本没有声明,则operator==隐式默认值。

上面的示例使用与 default 相同的算法operator<=>,如 cppreference 所解释的:

默认operator<=>通过依次比较 T 的基础(从左到右深度优先)和非静态成员(按声明顺序)子对象来计算 <=>,递归扩展数组成员(按增加下标的顺序)来执行字典比较),并在发现不相等的结果时提前停止

在 C++20 之前,您不能执行类似 的操作operator== = default,并且定义一个运算符不会导致定义其他运算符,例如以下无法使用 编译-std=c++17

#include <cassert>

struct Point {
    int x;
    int y;
    auto operator==(const Point& other) const {
        return x == other.x && y == other.y;
    };
};

int main() {
    Point pt1{1, 1}, pt2{1, 2};

    // Do some checks.
    assert(!(pt1 == pt2));
    assert( (pt1 != pt2));
}
Run Code Online (Sandbox Code Playgroud)

有错误:

main.cpp:16:18: error: no match for ‘operator!=’ (operand types are ‘Point’ and ‘Point’)
   16 |     assert( (pt1 != pt2));
      |              ~~~ ^~ ~~~
      |              |      |
      |              Point  Point
Run Code Online (Sandbox Code Playgroud)

然而,上面确实可以编译-std=c++20

相关:是否有基于其他操作符自动提供的 C++ 操作符重载?

在 Ubuntu 20.04、GCC 10.2.0 上测试。


归档时间:

查看次数:

26756 次

最近记录:

6 年,11 月 前