簡體   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:

結構 std::partial_ordering
結構 std::strong_ordering

我知道如果操作數具有整數類型,則運算符返回std::strong_ordering 我還知道操作數是否具有浮點類型,運算符會產生std::partial_ordering類型的PRvalue

但是為什么我應該使用三向比較運算符而不是雙向運算符( ==!=<<=>>= )? 這對我有好處嗎?

它可以在一次操作中確定順序
其他運算符需要兩次比較。

其他運營商總結:

  • 如果a == b為假,你不知道是a < b還是a > b
  • 如果a != b為真,你不知道是a < b還是a > b
  • 如果a < b為假,你不知道是a == b還是a > b
  • 如果a > b為假,你不知道是a == b還是a < b
  • 如果a <= b為真,你不知道是a == b還是a < b
  • 如果a >= b為真,你不知道是a == b還是a > b

一個簡潔的副作用是所有其他運算符都可以根據<=>來實現,並且編譯器可以為您生成它們。

另一個副作用是人們可能會對使用<=>作為數學中的等價箭頭感到困惑,自從打字機獲得這三個符號以來,幾乎一直如此。
(當且僅當ab相等時,我個人對a <=> b如何“真實”感到非常惱火。)

主要優點(至少對我而言)是這個運算符可以默認為 class,這將自動支持 class 的所有可能比較。 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;
}

以前,所有這些操作都必須在 class 中定義,這既麻煩又容易出錯 - 因為每當有新成員添加到 class 時,必須記住重新訪問這些操作。

用你自己的判斷。

飛船算子的重點不是專門用來比較物體的。 它的要點是允許編譯器從 spaceship 運算符綜合其他比較運算符。

如果您不需要特別回答小於、等於或大於的問題,則無需直接調用它。 使用對您有意義的運算符。

但是如果你需要使一個類型具有可比性,你只需要編寫 2 個函數(宇宙飛船和相等)而不是 6 個。在編寫這樣的 function 時,你可以在有問題的各個類型上使用 spaceship 運算符(它們應該具有可比性嗎?以這種方式)。 這使得實現這些功能變得更加容易。

宇宙飛船操作員允許您做的另一件有用的事情是告訴比較將提供什么的排序。 部分的,強烈的,或者其他的。 這在理論上可能很有用,但總體而言相當罕見。

飛船操作員由 Herb Sutter 提出並被委員會采用,並與 C++ 20 一起實施,詳細報告可以在這里查閱,或者如果你更喜歡講課,在這里你可以看到這個人自己為案例制作的視頻它。 在報告的第 3/4 頁中,您可以看到主要用例:

以下 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 ...
};

將被替換為:

class Point
{
    int x;
    int y;

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

因此,要回答您的問題,將operator<=>重載為 class 成員允許您對 class 對象使用所有比較運算符,而無需實現它們,默認它也默認為operator== ,如果它沒有另外聲明,這在術語中自動實現operator!= ,使所有比較操作都可以通過單個表達式進行。 此功能是主要用例。

我想指出,如果不引入與 C++20 默認比較功能,那么宇宙飛船運算符是不可能的。

默認三向比較

[...]
R為返回類型,每對子對象ab比較如下:
[...]
...如果Rstd::strong_ordering ,結果是:

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

否則,如果Rstd::weak_ordering ,則結果為:

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

否則( Rstd::partial_ordering ),結果是:

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

根據任何operator<=>重載的規則,默認的<=>重載也將允許將類型與<<=>>=進行比較。

如果operator<=>被默認並且operator==根本沒有聲明,那么operator==被隱式默認。

它還允許僅默認operator == ,這將實現operator != ,雖然不像前者那樣通用,但它也是一個有趣的可能性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM