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


214

当我试图了解C ++运算符,我偶然发现了一个奇怪的比较操作上cppreference.com*在一个看起来像这样的表:

在此处输入图片说明

我想:“好吧,如果它们是C ++中的常用运算符,我最好学习它们。” 但是我为阐明这个奥秘所做的所有尝试都没有成功。即使在这里,在Stack Overflow上我也没有运气。

<=>C ++之间是否有连接?

如果有的话,这个运算符的作用是什么?

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


82
@haccks:哦,拜托,我们还有很多问题甚至还没有被纳入标准之中。我们有一个C ++ 20标签是有原因的。这种东西很容易引起争议。
Nicol Bolas's

1
@ cubuspl42 bar< foo::operator<=>是一个类似于<--操作符的示例。
Yakk-Adam Nevraumont

8
@haccks:对。像C ++ 11一样,是有关实现C ++ 11的编译器的标记。C ++ 14是有关实现C ++ 14的编译器的标记。C ++ 17与实现C ++ 17的编译器有关。不,C ++ 20是有关C ++ 20的标签。而且由于这个问题是关于C ++ 20的,所以确实存在。错误的标签维基,而不是标签本身。
Nicol Bolas's

Answers:


179

这称为三向比较运算符

根据P0515的纸质提案:

有一个新的三向比较运算符<=>。表达式a <=> b返回其比较的对象<0如果a < b,比较>0如果a > b,并且比较==0,如果ab是相等的/当量。

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

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

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

cppreference说:

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

lhs <=> rhs   (1)  

该表达式返回一个对象

  • 比较<0是否lhs < rhs
  • 比较>0是否lhs > rhs
  • 和比较==0,如果lhsrhs是相等的/当量。

93
对于那些对“比较<0”,“比较>0”和“比较==0”的含义感到困惑的人(像我一样),它们的意思是<=>返回值是负值,正值或零值,具体取决于参数。很喜欢strncmpmemcmp
Cornstalks

1
@Dai即使两个'a' < 'a''c' < 'a'都为假,'a' < 'a'并且'a' < 'c'不是。在强顺序中,以下是正确的:a != ba < b || b < a
Revolver_Ocelot

1
@Revolver_Ocelot啊,所以可以将其定义为- operator==(T x, T y) { return !(x < y) && !(y < x); }operator!=(T x, T y) { return (x < y) || (y < x); }- 啊哈!当然,这效率不如true,==因为它两次调用比较,但仍然很简洁。

3
“强势回归”和“弱势回归”是什么意思?
lucidbrot

1
@hkBattousai表示比较后的对象返回< 0true。就是说,如果a < b那时(a <=> b) < 0总是如此。
rmobis

115

2017年11月11日,ISO C ++委员会采纳了 Herb Sutter提出的<=>“太空飞船”三向比较运算符的建议,将其作为C ++ 20中新增的功能之一。在名为“ 一致比较”的论文中,萨特,莫拉尔和布朗展示了新设计的概念。有关提案的概述,请参见以下文章的摘录:

表达一个<=> b返回,其比较的对象<0如果A <B ,比较> 0如果A> B,并且比较== 0如果a和b相等/当量。

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

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

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

  • 如果您的类型自然支持<,则返回_ordering,我们将有效地生成对称<><=> ===!=;否则返回_equality,我们将高效地生成对称==!=
  • 返回strong_如果你的类型一个== b意味着F(一)== F(B) (可替代性,其中˚F只读取比较隐状态是访问使用公共常量成员),否则返回 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 |             |
+------------------+------+------------+---------------+-------------+

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

  • strong_ordering与值{ lessequalgreater}隐式转换为:
    • weak_ordering用值{ lessequivalentgreater}
    • partial_ordering用值{ lessequivalentgreater}
    • strong_equality用值{ unequalequalunequal}
    • weak_equality用值{ nonequivalentequivalentnonequivalent}
  • weak_ordering与值{ lessequivalentgreater}隐式转换为:
    • partial_ordering用值{ lessequivalentgreater}
    • weak_equality用值{ nonequivalentequivalentnonequivalent}
  • partial_ordering与值{ lessequivalentgreaterunordered}隐式转换为:
    • weak_equality用值{ nonequivalentequivalentnonequivalentnonequivalent}
  • strong_equality值{ equalunequal}隐式转换为:
    • 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<=>和执行辞书的elementwise比较。没有<=>其他数组。
  • 因为void没有<=>

为了更好地了解此操作员的内部工作原理,请阅读原始文章。这就是我使用搜索引擎发现的内容。


1
好像cpp还不够复杂。为什么不简单地写一个比较方法……
Leandro

6
@Leandro宇宙飞船的运算符就是这种比较方法。此外,它可以正常工作并写入(或删除)其他六个比较运算符。我将采用一个比较运算符函数,该函数将写在六个单独的样板上。
匿名

请注意,这些_equality类型已经消失了:事实证明,这<=>与四个关系运算符配合得很好,但对两个相等运算符的配合却不那么理想(尽管有一些强烈的句法糖来支持您想要所有它们的常见情况)。
戴维斯鲱鱼

12

由于参考网页已更改,因此此答案变得无关紧要

您所引用网页已损坏。那天它被大量编辑,并且不同部分没有同步。当我查看时的状态是:

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

在页面底部,他们应该已经列出了相同的运算符,但是他们无所适从并添加了此将来的建议。

gcc还不知道<=>(并且-std=c++14永远不会),所以它认为您的意思是a <= > b。这是说明错误消息的原因。

如果五年后再尝试相同的操作,则可能会收到更好的错误消息,例如 <=> not part of C++14.


1
链接到网页的OP以及链接到的单独页面都是正确的。它<=>使用(自C ++ 20起)标签使操作符合格,告诉您期望使用哪个版本的标准。标准标签是cppreference.com遵循的约定。当然,您没有在时间机器中返回的编译器来为您提供支持,但是cpprefernce会(正确)告诉您期望什么。
斯宾塞

是的,但是...没有答案。您在评论...之类的。
qlp

2
我打算链接到与该问题相同的网页,但是没有找到。我想我回答了部分问题,其他答案未回答。我忽略了主要的粗体问题,因为其他人已经回答了。
Stig Hemmer
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.