![](/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.