简体   繁体   English

为什么要使用三向比较运算符 (<=>) 而不是双向比较运算符? 这有优势吗?

[英]Why should I use the three-way comparison operator (<=>) instead of the two-way comparison operators? Does this have an advantage?

#include <compare>
#include <iostream>

int main()
{ 
   auto comp1 = 1.1 <=> 2.2;
   auto comp2 = -1 <=> 1;
   std::cout << typeid(comp1).name()<<"\n"<<typeid(comp2).name();
}

Output: Output:

struct std::partial_ordering结构 std::partial_ordering
struct std::strong_ordering结构 std::strong_ordering

I know that if the operands have an integral type, the operator returns a PRvalue of type std::strong_ordering .我知道如果操作数具有整数类型,则运算符返回std::strong_ordering I also know if the operands have a floating-point type, the operator yields a PRvalue of type std::partial_ordering .我还知道操作数是否具有浮点类型,运算符会产生std::partial_ordering类型的PRvalue

But why should I use a three-way comparison operator instead of two-way operators ( == , != , < , <= , > , >= )?但是为什么我应该使用三向比较运算符而不是双向运算符( ==!=<<=>>= )? Is there an advantage this gives me?这对我有好处吗?

It makes it possible to determine the ordering in one operation.它可以在一次操作中确定顺序
The other operators require two comparisons.其他运算符需要两次比较。

Summary of the other operators:其他运营商总结:

  • If a == b is false, you don't know whether a < b or a > b如果a == b为假,你不知道是a < b还是a > b
  • If a != b is true, you don't know whether a < b or a > b如果a != b为真,你不知道是a < b还是a > b
  • If a < b is false, you don't know whether a == b or a > b如果a < b为假,你不知道是a == b还是a > b
  • If a > b is false, you don't know whether a == b or a < b如果a > b为假,你不知道是a == b还是a < b
  • If a <= b is true, you don't know whether a == b or a < b如果a <= b为真,你不知道是a == b还是a < b
  • If a >= b is true, you don't know whether a == b or a > b如果a >= b为真,你不知道是a == b还是a > b

A neat side effect is that all the other operators can be implemented in terms of <=> , and a compiler can generate them for you.一个简洁的副作用是所有其他运算符都可以根据<=>来实现,并且编译器可以为您生成它们。

Another side effect is that people might be confused by the use of <=> as the equivalence arrow in mathematics, which it has been pretty much since typewriters got those three symbols.另一个副作用是人们可能会对使用<=>作为数学中的等价箭头感到困惑,自从打字机获得这三个符号以来,几乎一直如此。
(I'm personally pretty miffed by how a <=> b is "truthy" if and only if a and b are not equivalent.) (当且仅当ab相等时,我个人对a <=> b如何“真实”感到非常恼火。)

The main advantage (at least for me) is the fact that this operator can be defaulted for the class, which will automatically support all possible comparisons for your class.主要优点(至少对我而言)是这个运算符可以默认为 class,这将自动支持 class 的所有可能比较。 Ie IE

#include <compare>

struct foo {
    int a;
    float b;
    auto operator<=>(const foo& ) const = default;
};

// Now all operations used before are defined for you automatically!

auto f1(const foo& l, const foo& r) {
    return l < r;
}

auto f2(const foo& l, const foo& r) {
    return l > r;
}

auto f3(const foo& l, const foo& r) {
    return l == r;
}

auto f4(const foo& l, const foo& r) {
    return l >= r;
}

auto f5(const foo& l, const foo& r) {
    return l <= r;
}

auto f6(const foo& l, const foo& r) {
    return l != r;
}

Previously, all those operations would have to be defined within the class, which is cumbersome and error-prone - as one would have to remember to revisit those whenever new members are added to the class.以前,所有这些操作都必须在 class 中定义,这既麻烦又容易出错 - 因为每当有新成员添加到 class 时,必须记住重新访问这些操作。

Use your own judgment.用你自己的判断。

The point of the spaceship operator is not specifically for comparing objects.飞船算子的重点不是专门用来比较物体的。 The main point of it is permitting the compiler to synthesize the other comparison operators from the spaceship operator.它的要点是允许编译器从 spaceship 运算符综合其他比较运算符。

If you don't specifically need to answer the question less-than, equal-to, or greater-than, then you don't need to invoke it directly.如果您不需要特别回答小于、等于或大于的问题,则无需直接调用它。 Use the operator that makes sense for you.使用对您有意义的运算符。

But should you need to make a type comparable, you only have to write 2 functions (spaceship and equality) rather than 6. And when writing such a function, you can use the spaceship operator on the individual types in question (should they be comparable in such a way).但是如果你需要使一个类型具有可比性,你只需要编写 2 个函数(宇宙飞船和相等)而不是 6 个。在编写这样的 function 时,你可以在有问题的各个类型上使用 spaceship 运算符(它们应该具有可比性吗?以这种方式)。 That makes it even easier to implement such functions.这使得实现这些功能变得更加容易。

The other useful thing that the spaceship operator allows you to do is tell what kind of ordering a comparison will provide.宇宙飞船操作员允许您做的另一件有用的事情是告诉比较将提供什么的排序。 Partial, strong, or whatever.部分的,强烈的,或者其他的。 This can theoretically be useful, but it's fairly rare overall.这在理论上可能很有用,但总体而言相当罕见。

The spaceship operator was proposed by Herb Sutter and was adopted by the committee to be implemented with C++ 20, detailed report can be consulted here , or you if are more into lectures, here you can see a video of the man himself making the case for it.飞船操作员由 Herb Sutter 提出并被委员会采用,并与 C++ 20 一起实施,详细报告可以在这里查阅,或者如果你更喜欢讲课,在这里你可以看到这个人自己为案例制作的视频它。 In pages 3/4 of the report you can see the main use case:在报告的第 3/4 页中,您可以看到主要用例:

The comparison operators implementation, needed for pre C++20, in the following class:以下 class 中需要 C++20 之前的比较运算符实现:

class Point
{
    int x;
    int y;

public:
    friend bool operator==(const Point &a, const Point &b) { return a.x == b.x && a.y == b.y; }
    friend bool operator<(const Point &a, const Point &b) { return a.x < b.x || (a.x == b.x && a.y < b.y); }
    friend bool operator!=(const Point &a, const Point &b) { return !(a == b); }
    friend bool operator<=(const Point &a, const Point &b) { return !(b < a); }
    friend bool operator>(const Point &a, const Point &b) { return b < a; }
    friend bool operator>=(const Point& a, const Point& b) { return !(a < b); }
    // ... non-comparisonfunctions ...
};

Would be replaced by:将被替换为:

class Point
{
    int x;
    int y;

public:
    auto operator<=>(const Point &) const = default; 
    // ... non-comparison functions ...
};

So to answer your question, overloading operator<=> as class member allows you to use all comparison operators for the class objects without having to implement them, defaulting it also defaults operator== , if it's not otherwise declared, which in term automatically implements operator!= , making all comparison operations available with a single expression.因此,要回答您的问题,将operator<=>重载为 class 成员允许您对 class 对象使用所有比较运算符,而无需实现它们,默认它也默认为operator== ,如果它没有另外声明,这在术语中自动实现operator!= ,使所有比较操作都可以通过单个表达式进行。 This functionality is the main use case.此功能是主要用例。

I would like to point out that the spaceship operator would not be possible without the introduction of the default comparison feature with C++20.我想指出,如果不引入与 C++20 默认比较功能,那么宇宙飞船运算符是不可能的。

Defaulted three-way comparison默认三向比较

[...] [...]
Let R be the return type, each pair of subobjects a , b is compared as follows:R为返回类型,每对子对象ab比较如下:
[...] [...]
... if R is std::strong_ordering , the result is: ...如果Rstd::strong_ordering ,结果是:

 a == b? R::equal: a < b? R::less: R::greater

Otherwise, if R is std::weak_ordering , the result is:否则,如果Rstd::weak_ordering ,则结果为:

 a == b? R::equivalent: a < b? R::less: R::greater

Otherwise ( R is std::partial_ordering ), the result is:否则( Rstd::partial_ordering ),结果是:

 a == b? R::equal: a < b? R::less: b < a? R::greater: R::unordered

Per the rules for any operator<=> overload, a defaulted <=> overload will also allow the type to be compared with < , <= , > , and >= .根据任何operator<=>重载的规则,默认的<=>重载也将允许将类型与<<=>>=进行比较。

If operator<=> is defaulted and operator== is not declared at all, then operator== is implicitly defaulted.如果operator<=>被默认并且operator==根本没有声明,那么operator==被隐式默认。

It also allows to default operator == only, which will implement operator != , albeit not as versatile as the former, it's also an interesting possibility.它还允许仅默认operator == ,这将实现operator != ,虽然不像前者那样通用,但它也是一个有趣的可能性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM