![](/img/trans.png)
[英]Why is ::operator new[] necessary when ::operator new is enough?
[英]Why must I provide 'operator ==' when 'operator <=>' is enough?
#include <compare>
struct A
{
int n;
auto operator<=>(A const& other) const
{
if (n < other.n)
{
return std::strong_ordering::less;
}
else if (n > other.n)
{
return std::strong_ordering::greater;
}
else
{
return std::strong_ordering::equal;
}
}
// compile error if the following code is commented out.
// bool operator==(A const& other) const
// { return n == other.n; }
};
int main()
{
A{} == A{};
}
看在線演示
當operator <=>
就足夠時,為什么我必須提供operator ==
?
當
operator<=>
足夠時,為什么我必須提供operator==
?
嗯,主要是因為這還不夠:-)
當 C++ 重寫你的語句時,相等和排序是不同的:
平等 | 訂購 | |
---|---|---|
基本的 | == | <=> |
中學 | != | <、>、<=、>= |
一級算子可以反轉,二級算子可以根據對應的一級算子改寫:
a == b
可以是:
a.operator==(b)
如果可用; 或者b.operator==(a)
如果不是。a != b
可以是:
! a.operator==(b)
! a.operator==(b)
如果可用最后一個也可以! b.operator==(a)
! b.operator==(a)
如果你必須重寫和反轉它(我不完全確定,因為我的經驗主要是比較相同的類型)。
但是默認情況下不跨等式/排序邊界進行重寫的要求意味着<=>
不是==
的重寫候選者。
平等和排序如此分開的原因可以在這篇 P1185 論文中找到, 該論文來自討論此問題的眾多標准會議之一。
在許多情況下,根據<=>
自動實現==
可能效率很低。 想到字符串、向量、數組或任何其他集合。 您可能不想使用<=>
來檢查兩個字符串的相等性:
"xxxxx(a billion other x's)"
; 和"xxxxx(a billion other x's)_and_a_bit_more"
。 那是因為<=>
必須處理整個字符串來計算排序,然后檢查排序是否強相等。
但是預先進行簡單的長度檢查會很快告訴您它們是不相等的。 這是 O(n) 時間復雜度(十億次左右的比較)和 O(1)(近乎立即的結果)之間的差異。
如果您知道這沒問題(或者您樂於忍受它可能帶來的任何性能損失),您始終可以默認相等。 但人們認為最好不要讓編譯器為您做出決定。
更詳細地,請考慮以下完整程序:
#include <iostream>
#include <compare>
class xyzzy {
public:
xyzzy(int data) : n(data) { }
auto operator<=>(xyzzy const &other) const {
// Could probably just use: 'return n <=> other.n;'
// but this is from the OPs actual code, so I didn't
// want to change it too much (formatting only).
if (n < other.n) return std::strong_ordering::less;
if (n > other.n) return std::strong_ordering::greater;
return std::strong_ordering::equal;
}
//auto operator==(xyzzy const &other) const {
// return n == other.n;
//}
//bool operator==(xyzzy const &) const = default;
private:
int n;
};
int main() {
xyzzy twisty(3);
xyzzy passages(3);
if (twisty < passages) std::cout << "less\n";
if (twisty == passages) std::cout << "equal\n";
}
它不會按原樣編譯,因為它需要一個operator==
作為最終語句。 但是你不必提供一個真正的(第一個注釋掉的塊),你可以告訴它使用默認值(第二個)。 而且,在這種情況下,這可能是正確的決定,因為使用默認值沒有真正的性能影響。
請記住,如果您明確提供三向比較運算符(當然,您使用==
或!=
,則只需要提供相等運算符。 如果你都沒有提供,C++ 會給你兩個默認值。
而且,即使您必須提供兩個函數(其中一個可能是默認函數),它仍然比以前更好,以前您必須明確提供它們,例如:
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)
。當“operator <=>”就足夠了時,為什么我必須提供“operator ==”?
因為不會用。
如果您要使用默認值就足夠了:
struct A
{
int n;
auto operator<=>(A const& other) const = default;
};
基本上, n == n
可能比(a <=> a) == std::strong_ordering::equal
更有效,並且在很多情況下這是一種選擇。 當您提供用戶定義的<=>
,語言實現無法知道后者是否可以替換為前者,也無法知道后者是否不必要地低效。
所以,如果你需要一個自定義的三向比較,那么你需要一個自定義的相等比較。 示例類不需要自定義的三向比較,因此您應該使用默認的比較。
查看之前的答案,沒有人解決另一個問題:出於排序目的,兩個對象可能相等但不相等。 例如,我可能想對 Unicode NFC 規范化中的字符串進行排序,並將大小寫轉換為小寫,但對於相等性測試,我想驗證字符串實際上是否相同,大小寫很重要,甚至可能區分 é 和 ´ + e 在輸入中。
是的,這是一個有點人為的示例,但它表明<=>
的定義不需要強排序,因此您不能依賴<=>
甚至可能返回std::strong_ordering::equal
。 使==
默認為<=>
返回std::strong_ordering::equal
不能假定為有效實現。
因為==
有時可以比使用a <=> b == 0
更快地實現,所以默認情況下編譯器拒絕使用潛在的次優實現。
例如考慮std::string
,它可以在循環元素之前檢查大小是否相同。
請注意,您不必手動實現==
。 您可以=default
it,它將根據<=>
實現它。
另請注意,如果您=default
<=>
本身,則不需要=default
ing ==
。
不,你沒有。 只需添加
bool operator==(A const& other) const = default;
https://godbolt.org/z/v1WGhxca6
您總是可以將它們重載為不同的語義。 為了防止意外的自動生成函數,需要= default
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.