Der Gleichheitsoperator wird für eine benutzerdefinierte Implementierung eines Raumschiffoperators in C++ 20 nicht definiert




c++20 spaceship-operator (2)

Ich habe ein seltsames Verhalten mit dem neuen Raumschiffoperator <=> in C ++ 20. Ich verwende Visual Studio 2019 Compiler mit /std:c++latest .

Dieser Code wird wie erwartet einwandfrei kompiliert:

#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;
}

Wenn ich jedoch X in dieses ändere:

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

Ich erhalte den folgenden Compilerfehler:

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

Ich habe es auch mit Clang versucht und ich bekomme ein ähnliches Verhalten.

Ich würde mich über eine Erklärung operator== , warum die Standardimplementierung den operator== korrekt generiert, die benutzerdefinierte jedoch nicht.


Bei der Standardisierung dieses Features wurde entschieden, dass Gleichheit und Reihenfolge logisch getrennt werden sollten. Daher rufen Gleichheitstests ( == und != ) Niemals den operator<=> . Es wurde jedoch nach wie vor als nützlich erachtet, beide mit einer einzigen Deklaration als Standard festlegen zu können. Wenn Sie also den Standardoperator operator<=> , wurde entschieden, dass Sie auch den Standardoperator operator== (es sei denn, Sie definieren ihn später oder haben ihn früher definiert).

In Bezug auf den Grund , warum diese Entscheidung getroffen wurde , geht die grundlegende Argumentation so. Betrachten Sie std::string . Die Reihenfolge zweier Zeichenfolgen ist lexikografisch. Jedes Zeichen hat einen ganzzahligen Wert, der mit jedem Zeichen in der anderen Zeichenfolge verglichen wird. Die erste Ungleichung ergibt das Ergebnis der Bestellung.

Gleichheitsprüfung von Strings hat jedoch einen Kurzschluss. Wenn die beiden Zeichenfolgen nicht gleich lang sind, macht es keinen Sinn, Zeichenvergleiche durchzuführen. Sie sind nicht gleich. Wenn also jemand Gleichheitstests durchführt, möchten Sie dies nicht auf lange Sicht tun, wenn Sie es kurzschließen können.

Es stellt sich heraus, dass viele Typen, die eine benutzerdefinierte Reihenfolge benötigen, auch einen Kurzschlussmechanismus für die Gleichheitsprüfung bieten. Um zu verhindern, dass nur operator<=> implementiert operator<=> und potenzielle Leistung verloren geht, zwingen wir alle effektiv dazu, beides zu tun.


Die anderen Antworten erklären sehr gut, warum die Sprache so ist. Ich wollte nur hinzufügen, dass es für den Fall, dass es nicht offensichtlich ist, natürlich möglich ist, einen vom Benutzer bereitgestellten operator<=> mit einem voreingestellten operator== . Sie müssen nur den voreingestellten operator== explizit schreiben:

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




spaceship-operator