簡體   English   中英

陣列上的宇宙飛船算子

[英]Spaceship operator on arrays

以下代碼旨在對包含數組的對象實現比較。 如果所有數組元素都這樣比較,則兩個對象應該比較為<,==,> 由於各種原因,以下內容無法編譯:

#include <compare>
class witharray {
private:
  array<int,4> the_array;
public:
  witharray( array<int,4> v )
    : the_array(v) {};
  int size() { return the_array.size(); };
  auto operator<=>( const witharray& other ) const {
    array< std::strong_ordering,4 > cmps;
    for (int id=0; id<4; id++)
      cmps[id] = the_array[id]<=>other.the_array[id];
    return accumulate
      (cmps.begin(),cmps.end(),
       std::equal,
       [] (auto x,auto y) -> std::strong_ordering { return x and y; }
       );
  };
};

首先,比較數組:

call to implicitly-deleted default constructor of 'array<std::strong_ordering, 4>

然后嘗試累積比較:

no matching function for call to 'accumulate'

編譯器資源管理器: https ://godbolt.org/z/E3ovh5qGa

還是我完全走錯了路?

請注意, std::array已經有 spaceship 運算符,顯然可以滿足您的需要:

class witharray {
private:
    array<int, 4> the_array;

public:
    witharray(array<int, 4> v)
        : the_array(v) {};
    int size() { return the_array.size(); };
    auto operator<=>(const witharray& other) const
    {
        return the_array <=> other.the_array;
    };
};

https://godbolt.org/z/4drddWa8G

現在涵蓋您的代碼的問題:

  • array< std::strong_ordering, 4 > cmps; 無法初始化,因為std::strong_ordering沒有默認值
  • 在這里使用std::accumluate很奇怪,有更好的算法: std::lexicographical_compare_three_way添加到處理宇宙飛船運算符
  • 您已經將std::equal提供為std::accumluate作為二進制操作,而實際上這是比較范圍的算法(它接受迭代器)。 您的計划很可能是使用std::equal_to

如果所有數組元素都這樣比較,則兩個對象應該比較為<==>

這是一個相當有趣的命令。 這里要注意的一件事是它是一個序。 也就是說,給定{1, 2} vs {2, 1} ,這些元素並不都是<==> 所以你留下了無序的。

C++20 的比較確實有辦法表示:你必須返回一個std::partial_ordering

我們可以實現這種排序的方式是我們首先比較第一個元素,然后我們確保所有其他元素比較相同。 如果任何一對元素的比較不同,那么我們就知道我們是無序的:

auto operator<=>( const witharray& other ) const
    -> std::partial_ordering
{
    std::strong_ordering c = the_array[0] <=> other.the_array[0];
    for (int i = 1; i < 4; ++i) {
        if ((the_array[i] <=> other.the_array[i]) != c) {
            return std::partial_ordering::unordered;
        }
    }
    return c;
}

這樣做的好處是不必比較每一對元素,因為我們可能在到達第二個元素時已經知道答案(例如{1, 2, x, x} vs {1, 3, x, x}已經是unordered ,不管其他元素是什么)。

這似乎是你試圖用你的accumulate來完成的,除了accumulate在這里是錯誤的算法,因為我們想早點停止。 在這種情況下,您需要all_of

auto comparisons = views::iota(0, 4)
    | views::transform([&](int i){
        return the_array[i] <=> other.the_array[i];
    });
bool all_match = ranges::all_of(comparisons | drop(1), [&](std::strong_ordering c){
    return c == comparisons[0];
});
return all_match ? comparisons[0] : std::partial_ordering::unordered;

誠然,這很尷尬。 在 C++23 中,我們可以更直接地comparisons部分:

auto comparisons = views::zip_transform(
    compare_three_way{}, the_array, other.the_array);

如果你有這樣的謂詞,它會更好讀:

bool all_match = ranges::all_of(comparisons | drop(1), equals(comparisons[0]));

或者為這個特定的用例編寫自己的算法(這是一個非常容易編寫的算法):

return all_same_value(comparisons)
    ? comparisons[0]
    : std::partial_ordering::unordered;

暫無
暫無

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

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