[英]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{};
}
See online demo看在线演示
Why must I provide operator ==
when operator <=>
is enough?当
operator <=>
就足够时,为什么我必须提供operator ==
?
Why must I provide
operator==
whenoperator<=>
is enough?当
operator<=>
足够时,为什么我必须提供operator==
?
Well, mainly because it's not enough :-)嗯,主要是因为这还不够:-)
Equality and ordering are different buckets when it comes time for C++ to rewrite your statements:当 C++ 重写你的语句时,相等和排序是不同的:
Equality![]() |
Ordering![]() |
|
---|---|---|
Primary![]() |
== ![]() |
<=> ![]() |
Secondary![]() |
!= ![]() |
<, >, <=, >= ![]() |
Primary operators have the ability to be reversed, and secondary operators have the ability to be rewritten in terms of their corresponding primary operator:一级算子可以反转,二级算子可以根据对应的一级算子改写:
a == b
can be either:a == b
可以是:
a.operator==(b)
if available; a.operator==(b)
如果可用; orb.operator==(a)
if not. b.operator==(a)
如果不是。a != b
can be:a != b
可以是:
! a.operator==(b)
! a.operator==(b)
if available ! a.operator==(b)
如果可用That last one could also be ! b.operator==(a)
最后一个也可以
! b.operator==(a)
! b.operator==(a)
if you have to rewrite and reverse it (I'm not entirely certain of that since my experience has mostly been with the same types being compared). ! b.operator==(a)
如果你必须重写和反转它(我不完全确定,因为我的经验主要是比较相同的类型)。
But the requirement that rewriting not take place by default across the equality/ordering boundary means that <=>
is not a rewrite candidate for ==
.但是默认情况下不跨等式/排序边界进行重写的要求意味着
<=>
不是==
的重写候选者。
The reason why equality and ordering are separated like that can be found in this P1185 paper , from one of the many standards meetings that discussed this.平等和排序如此分开的原因可以在这篇 P1185 论文中找到, 该论文来自讨论此问题的众多标准会议之一。
There are many scenarios where automatically implementing ==
in terms of <=>
could be quite inefficient.在许多情况下,根据
<=>
自动实现==
可能效率很低。 String, vector, array, or any other collections come to mind.想到字符串、向量、数组或任何其他集合。 You probably don't want to use
<=>
to check the equality of the two strings:您可能不想使用
<=>
来检查两个字符串的相等性:
"xxxxx(a billion other x's)"
; "xxxxx(a billion other x's)"
; and"xxxxx(a billion other x's)_and_a_bit_more"
. "xxxxx(a billion other x's)_and_a_bit_more"
。 That's because <=>
would have to process the entire strings to work out ordering and then check if the ordering was strong-equal.那是因为
<=>
必须处理整个字符串来计算排序,然后检查排序是否强相等。
But a simple length check upfront would tell you very quickly that they were unequal.但是预先进行简单的长度检查会很快告诉您它们是不相等的。 This is the difference between O(n) time complexity, a billion or so comparisons, and O(1), a near-immediate result.
这是 O(n) 时间复杂度(十亿次左右的比较)和 O(1)(近乎立即的结果)之间的差异。
You can always default equality if you know it will be okay (or you're happy to live with any performance hit it may come with).如果您知道这没问题(或者您乐于忍受它可能带来的任何性能损失),您始终可以默认相等。 But it was thought best not to have the compiler make that decision for you.
但人们认为最好不要让编译器为您做出决定。
In more detail, consider the following complete program:更详细地,请考虑以下完整程序:
#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";
}
It won't compile as-is since it needs an operator==
for the final statement.它不会按原样编译,因为它需要一个
operator==
作为最终语句。 But you don't have to provide a real one (the first commented-out chunk), you can just tell it to use the default (the second).但是你不必提供一个真正的(第一个注释掉的块),你可以告诉它使用默认值(第二个)。 And, in this case, that's probably the correct decision as there's no real performance impact from using the default.
而且,在这种情况下,这可能是正确的决定,因为使用默认值没有真正的性能影响。
Keep in mind that you only need to provide an equality operator if you explicitly provide a three-way comparison operator (and you use ==
or !=
, of course).请记住,如果您明确提供三向比较运算符(当然,您使用
==
或!=
,则只需要提供相等运算符。 If you provide neither, C++ will give you both defaults.如果你都没有提供,C++ 会给你两个默认值。
And, even though you have to provide two functions (with one possibly being a defaulted one), it's still better than previously, where you had to explicitly provide them all, something like:而且,即使您必须提供两个函数(其中一个可能是默认函数),它仍然比以前更好,以前您必须明确提供它们,例如:
a == b
. a == b
。a < b
. a < b
。a != b
, defined as ! (a == b)
a != b
,定义为! (a == b)
! (a == b)
. ! (a == b)
。a > b
, defined as ! (a < b || a == b)
a > b
,定义为! (a < b || a == b)
! (a < b || a == b)
. ! (a < b || a == b)
。a <= b
, defined as a < b || a == b
a <= b
,定义为a < b || a == b
a < b || a == b
. a < b || a == b
。a >= b
, defined as ! (a < b)
a >= b
,定义为! (a < b)
! (a < b)
. ! (a < b)
。Why must I provide 'operator ==' when 'operator <=>' is enough?
当“operator <=>”就足够了时,为什么我必须提供“operator ==”?
Because it won't be used.因为不会用。
It will be enough if you were to use the defaulted one:如果您要使用默认值就足够了:
struct A
{
int n;
auto operator<=>(A const& other) const = default;
};
Basically, n == n
is potentially more efficient than (a <=> a) == std::strong_ordering::equal
and there are many cases where that is an option.基本上,
n == n
可能比(a <=> a) == std::strong_ordering::equal
更有效,并且在很多情况下这是一种选择。 When you provide a user defined <=>
, the language implementation cannot know whether latter could be substituted with the former, nor can it know whether latter is unnecessarily inefficient.当您提供用户定义的
<=>
,语言实现无法知道后者是否可以替换为前者,也无法知道后者是否不必要地低效。
So, if you need a custom three way comparison, then you need a custom equality comparison.所以,如果你需要一个自定义的三向比较,那么你需要一个自定义的相等比较。 The example class doesn't need a custom three way comparison, so you should use the default one.
示例类不需要自定义的三向比较,因此您应该使用默认的比较。
Looking at the previous answers, nobody has addressed another issue: For ordering purposes, two objects might be equivalent and yet not be equal.查看之前的答案,没有人解决另一个问题:出于排序目的,两个对象可能相等但不相等。 For example, I might want to sort on strings in Unicode NFC normalization with case-folding to lowercase, but for equality testing, I want to verify that the strings are actually identical, with case being significant and perhaps even distinguishing between é and ´ + e in the input.
例如,我可能想对 Unicode NFC 规范化中的字符串进行排序,并将大小写转换为小写,但对于相等性测试,我想验证字符串实际上是否相同,大小写很重要,甚至可能区分 é 和 ´ + e 在输入中。
Yes, this is a somewhat contrived example, but it serves to make the point that the definition of <=>
does not require strong ordering so you cannot rely on <=>
even potentially returning std::strong_ordering::equal
.是的,这是一个有点人为的示例,但它表明
<=>
的定义不需要强排序,因此您不能依赖<=>
甚至可能返回std::strong_ordering::equal
。 Making ==
default to <=>
returns std::strong_ordering::equal
cannot be assumed to be a valid implementation.使
==
默认为<=>
返回std::strong_ordering::equal
不能假定为有效实现。
Because ==
can sometimes be implemented faster than using a <=> b == 0
, so the compiler refuses to use potentially suboptimal implementation by default.因为
==
有时可以比使用a <=> b == 0
更快地实现,所以默认情况下编译器拒绝使用潜在的次优实现。
Eg consider std::string
, which can check if sizes are the same before looping over the elements.例如考虑
std::string
,它可以在循环元素之前检查大小是否相同。
Note that you don't have to implement ==
manually.请注意,您不必手动实现
==
。 You can =default
it, which will implement it in terms of <=>
.您可以
=default
it,它将根据<=>
实现它。
Also note that if you =default
<=>
itself, then =default
ing ==
is not necessary.另请注意,如果您
=default
<=>
本身,则不需要=default
ing ==
。
No, you don't.不,你没有。 Just add
只需添加
bool operator==(A const& other) const = default;
https://godbolt.org/z/v1WGhxca6 https://godbolt.org/z/v1WGhxca6
You can always overload them to different semantics.您总是可以将它们重载为不同的语义。 To prevent unexpected auto generated function, the
= default
is needed为了防止意外的自动生成函数,需要
= default
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.