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

前端 未结 3 397
野性不改
野性不改 2020-12-30 18:25

I\'m running into a strange behavior with the new spaceship operator <=> in C++20. I\'m using Visual Studio 2019 compiler with /std:c++latest

相关标签:
3条回答
  • 2020-12-30 18:59

    This is by design.

    [class.compare.default] (emphasis mine)

    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.

    Only a defaulted <=> allows a synthesized == to exist. The rationale is that classes like std::vector cannot use a defaulted <=>. In addition, 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 ==. Thus, instead of generating a non-sensible default, the language leaves it up to the programmer.

    0 讨论(0)
  • 2020-12-30 19:00

    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==. You just need to explicitly write the defaulted operator==:

    struct X
    {
        int Dummy = 0;
        auto operator<=>(const X& other) const
        {
            return Dummy <=> other.Dummy;
        }
        bool operator==(const X& other) const = default;
    };
    
    0 讨论(0)
  • 2020-12-30 19:09

    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<=>. 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).

    As to why this decision was made, the basic reasoning goes like this. Consider std::string. Ordering of two strings is lexicographical; each character has its integer value compared against each character in the other string. 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.

    0 讨论(0)
提交回复
热议问题