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

时间:2017-11-24 04:26:17

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

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

enter image description here

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

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

如果有,这个操作员到底做了什么?

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

5 个答案:

答案 0 :(得分:166)

这称为三向比较运算符。

根据P0515论文提案:

  

有一个新的三向比较运算符<=>。表达式a <=> b会返回一个对象,该对象会比较<0 a < b>0 a > b==0 a boperator<=>相等/相等。

     

要为您的类型编写所有比较,只需编写<即可   返回适当的类别类型:

     
      
  • 如果您的类型自然支持<,则返回一个_ordering ,我们将有效地生成><=>===!=a == b;   否则返回 _equality ,我们将有效地生成    == !=

  •   
  • 如果您的类型f(a) == f(b)隐含lhs <=> rhs (1) (可替代性,其中f只读取比较显着状态),则返回强   可以使用nonprivate const接口访问),否则返回   弱。

  •   

cppreference说:

  

三向比较运算符表达式的格式为

<0
     

表达式返回一个

对象      
      
  • 比较lhs < rhs if >0
  •   
  • 比较lhs > rhs if ==0
  •   
  • 并比较lhs如果rhscsv.reader相等/等效。
  •   

答案 1 :(得分:103)

2017-11-11上,ISO C ++委员会通过了Herb Sutter&lt; =&gt;的建议。 “太空飞船”三向比较运算符是添加到 C ++ 20 的新功能之一。在题为Consistent comparison Sutter的论文中,Maurer和Brown展示了新设计的概念。有关该提案的概述,请参阅以下文章摘录:

  

表达式 a&lt; =&gt; b 返回一个比较&lt; 0 的对象,如果 a&lt;   b ,比较&gt; 0 如果 a&gt; b ,如果a和b为,则比较 == 0   等于/当量。

     

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

auto X::operator<=>(const Y&) =default;
     

高级案例:要为类型为 Y X 编写所有比较,只需编写运算符&lt; =&gt; < / strong>需要 Y ,可以使用   如果需要, = default 获取成员语义,并返回   适当的类别类型:

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

比较类别

五个比较类别被定义为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 |             |
+------------------+------+------------+---------------+-------------+

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

    值为{strong_orderinglessequal}的
  • greater隐式转换为:
    • weak_ordering的值为{lessequivalentgreater}
    • partial_ordering的值为{lessequivalentgreater}
    • strong_equality的值为{unequalequalunequal}
    • weak_equality的值为{nonequivalentequivalentnonequivalent}
  • 值为{weak_orderinglessequivalent}的
  • greater隐式转换为:
    • partial_ordering的值为{lessequivalentgreater}
    • weak_equality的值为{nonequivalentequivalentnonequivalent}
  • 值为{partial_orderinglessequivalentgreater}的
  • unordered隐式转换为:
    • weak_equality的值为{nonequivalentequivalentnonequivalentnonequivalent}
  • 值为{strong_equalityequal}的
  • unequal隐式转换为:
    • weak_equality,其值为{equivalentnonequivalent}

三方比较

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

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

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

  • 对于bool,积分和指针类型,<=>会返回strong_ordering
  • 对于指针类型,允许使用不同的cv资格和派生到基础的转换来调用同构的内置<=>,并且内置异构operator<=>(T*, nullptr_t)。只有对同一对象/分配的指针的比较才是常量表达式。
  • 对于基本浮点类型,<=>返回partial_ordering,并且可以通过将参数扩展为更大的浮点类型来异步调用。
  • 对于枚举,<=>返回与枚举的基础类型<=>相同的内容。
  • 对于nullptr_t<=>返回strong_ordering并始终收益equal
  • 对于可复制数组,T[N] <=> T[N]返回与T的{​​{1}}相同的类型,并执行词典元素比较。其他阵列没有<=>
  • 对于<=>,没有void

为了更好地理解此运算符的内部工作原理,请阅读原始paper。这正是我发现使用搜索引擎的原因。

答案 2 :(得分:11)

由于引用的网页已更改

,此答案已无关紧要

web page you are referencing被打破了。那天正在编辑很多,不同的部分不同步。我在看它时的状态是:

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

在页面底部,他们应该列出相同的操作符,但是他们会蠢蠢欲动,并添加了这个未来的建议。

gcc尚未了解<=>(和-std=c++14,永远不会),所以 它认为你的意思是a <= > b。这解释了错误消息。

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

答案 3 :(得分:1)

默认<=>自动给出==, !=, <, >, <=, >=

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

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

main.cpp

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

    // Do some checks.
    assert(!(pt1 == pt2));
    assert( (pt1 != pt2));
    assert( (pt1 <  pt2));
    assert( (pt1 <= pt2));
    assert(!(pt1 >  pt2));
    assert(!(pt1 >= pt2));
}

编译并运行:

sudo apt install g++-10
g++-10 -ggdb3 -O0 -std=c++20 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

上述的等效更明确的版本是:

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

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

根据任何operator<=>重载的规则,默认的<=>重载还将允许将类型与<<=>,和>=

如果默认设置为operator<=>,而根本没有声明operator==,则默认设置为operator==

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

默认的operator<=>通过依次比较T的基础(从左到右的深度优先)然后是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));
}

有错误:

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

上面的代码确实在-std=c++20下编译。

相关:Are any C++ operator overloads provided automatically based on others?

在Ubuntu 20.04,GCC 10.2.0上进行了测试。

答案 4 :(得分:0)

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

该表达式返回对象如下;

auto cmp  = a <=> b;

cmp > 0 if a > b
cmp = 0 if a == b
cmp < 0 if a < b  

示例程序

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

}

如何编译和运行?

g++-10 threewaycmp.cpp -std=c++20
./a.out

结果

lhs is less than rhs

请参考以下链接了解更多详情 https://en.cppreference.com/w/cpp/language/operator_comparison