为什么我必须提供足够的时间operator==
?operator<=>
好吧,主要是因为这还不够:-)
当 C++ 重写你的语句时,相等和排序是不同的桶:
|
平等 |
订购 |
基本的 |
== |
<=> |
中学 |
!= |
<, >, <=, >= |
主算子有反转的能力,二级算子有能力根据其对应的主算子改写:
- 反转意味着
a == b
可以是:
a.operator==(b)
如果可供使用的话; 或者
b.operator==(a)
如果不。
- 重写意味着
a != b
可以:
! a.operator==(b)
如果可供使用的话
! 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==
for final 语句。但是您不必提供真实的(第一个注释掉的块),您可以告诉它使用默认值(第二个)。而且,在这种情况下,这可能是正确的决定,因为使用默认值不会对性能产生真正的影响。
请记住,如果您明确提供三路比较运算符(并且您当然使用==
or ) ,您只需要提供一个相等运算符!=
。如果您都不提供,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)
。