[英]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::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.