简体   繁体   English

非默认运算符 <=> 在 C++20 中不会生成 == 和 !=

[英]non-defaulted operator <=> doesn't generate == and != in C++20

I'm running into a strange behavior with the new spaceship operator <=> in C++20.我在 C++20 中使用新的宇宙飞船运算符<=>遇到了一个奇怪的行为。 I'm using Visual Studio 2019 compiler with /std:c++latest .我正在使用带有/std:c++latest的 Visual Studio 2019 编译器。

This code compiles fine, as expected:正如预期的那样,这段代码编译得很好:

#include <compare>

struct X
{
    int Dummy = 0;
    auto operator<=>(const X&) const = default; // Default implementation
};

int main()
{
    X a, b;

    a == b; // OK!

    return 0;
}

However, if I change X to this:但是,如果我将X更改为:

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
};

I get the following compiler error:我收到以下编译器错误:

error C2676: binary '==': 'X' does not define this operator or a conversion to a type acceptable to the predefined operator

I tried this on clang as well, and I get similar behavior.我也在 clang 上试过这个,我得到了类似的行为。

I would appreciate some explanation on why the default implementation generates operator== correctly, but the custom one doesn't.我希望能解释一下为什么默认实现会正确生成operator== ,但自定义的却不会。

This is by design.这是设计使然。

[class.compare.default] (emphasis mine) [class.compare.default] (强调我的)

3 If the class definition does not explicitly declare an == operator function, but declares a defaulted three-way comparison operator function, an == operator function is declared implicitly with the same access as the three-way comparison operator function. 3 If the class definition does not explicitly declare an == operator function, but declares a defaulted three-way comparison operator function, an == operator function is declared implicitly with the same access as the three-way comparison operator function. The implicitly-declared == operator for a class X is an inline member and is defined as defaulted in the definition of X. class X 的隐式声明==运算符是内联成员,在 X 的定义中定义为默认值。

Only a defaulted <=> allows a synthesized == to exist.只有默认的<=>允许合成的==存在。 The rationale is that classes like std::vector should not use a non-defaulted <=> for equality tests.基本原理是像std::vector这样的类不应该使用非默认的<=>进行相等性测试。 Using <=> for == is not the most efficient way to compare vectors.==使用<=>并不是比较向量的最有效方法。 <=> must give the exact ordering, whereas == may bail early by comparing sizes first. <=>必须给出确切的顺序,而==可能会通过首先比较大小来提前放弃。

If a class does something special in its three-way comparison, it will likely need to do something special in its == .如果 class 在其三路比较中做了一些特别的事情,它可能需要在其==中做一些特别的事情。 Thus, instead of generating a potentially non-sensible default, the language leaves it up to the programmer.因此,语言不会生成潜在的不合理的默认值,而是将其留给程序员。

During the standardization of this feature, it was decided that equality and ordering should logically be separated.在此功能的标准化过程中,决定在逻辑上将相等和排序分开。 As such, uses of equality testing ( == and != ) will never invoke operator<=> .因此,相等测试( ==!= )的使用永远不会调用operator<=> However, it was still seen as useful to be able to default both of them with a single declaration.但是,能够通过一个声明默认它们两者仍然被认为是有用的。 So if you default operator<=> , it was decided that you also meant to default operator== (unless you define it later or had defined it earlier).因此,如果您默认operator<=> ,则决定您也意味着默认operator== (除非您稍后定义它或之前定义它)。

As to why this decision was made , the basic reasoning goes like this.至于为什么做出这个决定,基本的推理是这样的。 Consider std::string .考虑std::string Ordering of two strings is lexicographical;两个字符串的排序是按字典顺序排列的; each character has its integer value compared against each character in the other string.每个字符都有其 integer 值与另一个字符串中的每个字符进行比较。 The first inequality results in the result of ordering.第一个不等式导致排序的结果。

However, equality testing of strings has a short-circuit.但是,字符串的相等性测试有一个短路。 If the two strings aren't of equal length, then there's no point in doing character-wise comparison at all;如果两个字符串的长度不相等,那么进行字符比较就没有意义了。 they aren't equal.他们不平等。 So if someone is doing equality testing, you don't want to do it long-form if you can short-circuit it.因此,如果有人在做平等测试,如果你能把它短路,你就不想做长篇大论。

It turns out that many types that need a user-defined ordering will also offer some short-circuit mechanism for equality testing.事实证明,许多需要用户定义排序的类型也会为相等性测试提供一些短路机制。 To prevent people from implementing only operator<=> and throwing away potential performance, we effectively force everyone to do both.为了防止人们只实现operator<=>并放弃潜在的性能,我们有效地强迫每个人都做这件事。

The other answers explain really well why the language is like this.其他答案很好地解释了为什么这种语言是这样的。 I just wanted to add that in case it's not obvious, it is of course possible to have a user-provided operator<=> with a defaulted operator== .我只是想补充一点,以防不明显,当然可以有一个用户提供的operator<=>和一个默认的operator== You just need to explicitly write the defaulted operator== :您只需要显式编写默认的operator==

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
    bool operator==(const X& other) const = default;
};

Note that the defaulted operator== performs memberwise == comparisons.请注意,默认的operator==执行成员==比较。 That is to say, it is not implemented in terms of the user-provided operator<=> .也就是说,它不是按照用户提供的operator<=>来实现的。 So requiring the programmer to explicitly ask for this is a minor safety feature to help prevent surprises.因此,要求程序员明确要求这是一个有助于防止意外的次要安全功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM