Was ist der Operator <=> in C ++?


215

Während ich versuche , darüber zu erfahren , C ++ Operatoren, stieß ich auf einem seltsamen Vergleichsoperator auf cppreference.com , * in einer Tabelle , die wie folgt aussah:

Geben Sie hier die Bildbeschreibung ein

"Nun, wenn dies in C ++ übliche Operatoren sind, lerne ich sie besser", dachte ich. Aber alle meine Versuche, dieses Rätsel zu lösen, waren erfolglos. Selbst hier bei Stack Overflow hatte ich kein Glück bei meiner Suche.

Gibt es eine Verbindung zwischen <=> und C ++ ?

Und wenn ja, was macht dieser Operator genau?

* In der Zwischenzeit hat cppreference.com diese Seite aktualisiert und enthält nun Informationen zum <=>Betreiber.


82
@haccks: Oh bitte, wir hatten viele Fragen zu Sachen, die nicht einmal in den Standard aufgenommen wurden. Wir haben aus einem bestimmten Grund ein C ++ 20-Tag. Diese Art von Sachen ist sehr thematisch.
Nicol Bolas

1
@ cubuspl42 bar< foo::operator<=>ist ein Beispiel dafür, wie es wie der <--Operator sein könnte.
Yakk - Adam Nevraumont

8
@haccks: Richtig. Wie C ++ 11 ist ein Tag über Compiler, die C ++ 11 implementieren. Und C ++ 14 ist ein Tag über Compiler, die C ++ 14 implementieren. In C ++ 17 geht es um Compiler, die C ++ 17 implementieren. Nein, C ++ 20 ist das Tag für Dinge über C ++ 20. Und da es sich bei dieser Frage um C ++ 20 handelt, ist sie da. Das Tag-Wiki, das falsch war, nicht das Tag selbst.
Nicol Bolas

Antworten:


180

Dies wird als Drei-Wege-Vergleichsoperator bezeichnet .

Gemäß dem Papiervorschlag P0515 :

Es gibt einen neuen Drei-Wege-Vergleichsoperator <=>. Der Ausdruck a <=> bgibt ein Objekt , das vergleicht , <0ob a < bvergleicht , >0wenn a > b, und vergleicht , ==0ob aund bgleich / Äquivalent.

Um alle Vergleiche für Ihren Typ zu schreiben operator<=>, schreiben Sie einfach, dass der entsprechende Kategorietyp zurückgegeben wird:

  • Rück ein _ordering wenn Ihre Art natürlich unterstützt <, und wir werden effizient erzeugen <, >, <=, >=, ==, und !=; Andernfalls geben Sie eine _equality zurück , und wir generieren == und ! = effizient .

  • Geben Sie stark zurück, wenn dies für Ihren Typ a == bimpliziert f(a) == f(b)(Substituierbarkeit, wobei f nur den Vergleichsstatus liest, auf den über die nichtprivate const-Schnittstelle zugegriffen werden kann), andernfalls geben Sie schwach zurück.

Die Referenz sagt:

Die Drei-Wege-Vergleichsoperatorausdrücke haben die Form

lhs <=> rhs   (1)  

Der Ausdruck gibt ein Objekt zurück, das

  • vergleicht <0wennlhs < rhs
  • vergleicht >0wennlhs > rhs
  • und vergleicht, ==0ob lhsund rhsgleich / äquivalent sind.

93
Für diejenigen, die verwirrt sind (wie ich), was "Vergleichen <0", "Vergleichen >0" und "Vergleichen ==0" bedeutet, bedeutet dies, dass die <=>Rückgabe je nach Argument einen negativen, positiven oder Nullwert ergibt. Ähnlich wie strncmpund memcmp.
Cornstalks

1
@Dai obwohl beide 'a' < 'a'und 'c' < 'a'beide falsch sind 'a' < 'a'und 'a' < 'c'nicht. In starker Reihenfolge ist folgendes wahr: a != ba < b || b < a
Revolver_Ocelot

1
@Revolver_Ocelot Ah, also kann es definiert und generiert werden als operator==(T x, T y) { return !(x < y) && !(y < x); }und operator!=(T x, T y) { return (x < y) || (y < x); }- ah-ha! Dies ist natürlich weniger effizient als ein True, ==da es den Vergleich zweimal aufruft, aber immer noch ordentlich.
Dai

3
Was bedeuten "stark zurückkehren" und "schwach zurückkehren"?
Lucidbrot

2
@hkBattousai bedeutet, dass das Objekt zurückgegeben wird, wenn es im Vergleich < 0zu true ausgewertet wird. Das heißt, wenn a < bdann (a <=> b) < 0immer wahr ist.
RMOBIS

116

Am 11.11.2017 nahm das ISO C ++ - Komitee den Vorschlag von Herb Sutter für den Dreiwege-Vergleichsoperator <=> "Raumschiff" als eine der neuen Funktionen an, die C ++ 20 hinzugefügt wurden . In dem Artikel mit dem Titel Konsistenter Vergleich Sutter demonstrieren Maurer und Brown die Konzepte des neuen Designs. Für einen Überblick über den Vorschlag hier ein Auszug aus dem Artikel:

Der Ausdruck a <=> b gibt ein Objekt zurück, das <0 vergleicht, wenn a <b , > 0 vergleicht, wenn a> b , und == 0 vergleicht, wenn a und b gleich / äquivalent sind.

Häufiger Fall: Um alle Vergleiche für Ihren Typ X mit Typ Y mit Mitgliedssemantik zu schreiben, schreiben Sie einfach:

auto X::operator<=>(const Y&) =default;

Erweiterte Fälle: Um alle Vergleiche für Ihren Typ X mit Typ Y zu schreiben, schreiben Sie einfach den Operator <=> , der ein Y annimmt. Verwenden Sie = default , um bei Bedarf eine Semantik auf Mitgliedsebene abzurufen, und geben Sie den entsprechenden Kategorietyp zurück:

  • Geben Sie eine _ordering zurück, wenn Ihr Typ natürlich < unterstützt und wir effizient symmetrische < , > , <= , > = , == und ! = Generieren . Andernfalls geben Sie eine _Equality zurück , und wir generieren effizient symmetrische == und ! = .
  • Geben Sie strong_ zurück, wenn für Ihren Typ a == b f (a) == f (b) impliziert (Substituierbarkeit, wobei f nur den Vergleichsstatus liest, auf den mit den öffentlichen const- Mitgliedern zugegriffen werden kann ), andernfalls geben Sie schwach_ zurück .

Vergleichskategorien

Fünf Vergleichskategorien werden als std::Typen definiert , die jeweils die folgenden vordefinierten Werte aufweisen:

+--------------------------------------------------------------------+
|                  |          Numeric  values          | Non-numeric |
|     Category     +-----------------------------------+             |
|                  | -1   | 0          | +1            |   values    |
+------------------+------+------------+---------------+-------------+
| strong_ordering  | less | equal      | greater       |             |
| weak_ordering    | less | equivalent | greater       |             |
| partial_ordering | less | equivalent | greater       | unordered   |
| strong_equality  |      | equal      | nonequal      |             |
| weak_equality    |      | equivalent | nonequivalent |             |
+------------------+------+------------+---------------+-------------+

Implizite Konvertierungen zwischen diesen Typen sind wie folgt definiert:

  • strong_orderingmit Werten { less, equal, greater} konvertiert implizit auf:
    • weak_orderingmit Werten { less, equivalent, greater}
    • partial_orderingmit Werten { less, equivalent, greater}
    • strong_equalitymit Werten { unequal, equal, unequal}
    • weak_equalitymit Werten { nonequivalent, equivalent, nonequivalent}
  • weak_orderingmit Werten { less, equivalent, greater} konvertiert implizit auf:
    • partial_orderingmit Werten { less, equivalent, greater}
    • weak_equalitymit Werten { nonequivalent, equivalent, nonequivalent}
  • partial_orderingmit Werten { less, equivalent, greater, unordered} konvertiert implizit auf:
    • weak_equalitymit Werten { nonequivalent, equivalent, nonequivalent, nonequivalent}
  • strong_equalitymit Werten { equal, unequal} wird implizit konvertiert in:
    • weak_equalitymit Werten { equivalent, nonequivalent}

Drei-Wege-Vergleich

Das <=>Token wird eingeführt. Die Zeichenfolge wird im alten Quellcode mit einem <=>Token versehen <= >. Muss beispielsweise X<&Y::operator<=>ein Leerzeichen hinzufügen, um seine Bedeutung beizubehalten.

Der überladbare Operator <=>ist eine Drei-Wege-Vergleichsfunktion und hat Vorrang höher als <und niedriger als <<. Es gibt einen Typ zurück, der mit Literal verglichen werden kann, 0aber andere Rückgabetypen sind zulässig, z. B. zur Unterstützung von Ausdrucksvorlagen. Alle <=>in der Sprache und in der Standardbibliothek definierten Operatoren geben einen der 5 oben genannten std::Vergleichskategorietypen zurück.

Für Sprachtypen werden die folgenden integrierten <=>Vergleiche desselben Typs bereitgestellt. Alle sind constexpr , sofern nicht anders angegeben. Diese Vergleiche können nicht heterogen mit skalaren Promotions / Conversions aufgerufen werden.

  • Für boolIntegral- und Zeigertypen wird <=>zurückgegeben strong_ordering.
  • Bei Zeigertypen können die verschiedenen CV-Qualifikationen und Konvertierungen von abgeleiteten zu Basis eine homogene integrierte Funktion aufrufen <=>, und es sind integrierte heterogene Funktionen vorhanden operator<=>(T*, nullptr_t). Nur Vergleiche von Zeigern auf dasselbe Objekt / dieselbe Zuordnung sind konstante Ausdrücke.
  • Gibt für grundlegende Gleitkommatypen <=>zurück partial_orderingund kann heterogen aufgerufen werden, indem Argumente auf einen größeren Gleitkommatyp erweitert werden.
  • Gibt für Aufzählungen <=>dasselbe zurück wie die zugrunde liegenden Typen der Aufzählung <=>.
  • Für nullptr_t, <=>kehrt strong_orderingund immer Ausbeuten equal.
  • Gibt für kopierbare Arrays T[N] <=> T[N]den gleichen Typ wie T's zurück <=>und führt einen lexikografischen elementweisen Vergleich durch. Es gibt keine <=>für andere Arrays.
  • Denn voides gibt keine <=>.

Zum besseren Verständnis der Funktionsweise von diesem Betreiber zu verstehen, benutzen Sie bitte das Original lesen Papier . Dies ist genau das, was ich mithilfe von Suchmaschinen herausgefunden habe.


1
Als ob cpp nicht schon komplex genug wäre. Warum nicht einfach eine Vergleichsmethode schreiben ...
Leandro

6
@Leandro Der Raumschiffoperator ist diese Vergleichsmethode. Außerdem funktioniert es einfach und schreibt (oder löscht) die sechs anderen Vergleichsoperatoren. Ich nehme eine Vergleichsoperatorfunktion, die über sechs einzelne Kesselplatten geschrieben ist.
anonym

Beachten Sie, dass die _equalityTypen gestorben sind: Es stellte sich heraus, dass dies <=>mit den vier relationalen Operatoren gut funktioniert, aber nicht so gut mit den beiden Gleichheitsoperatoren (obwohl es einen intensiven syntaktischen Zucker gibt, der den allgemeinen Fall unterstützt, in dem Sie alle wollen).
Davis Herring

12

Diese Antwort ist irrelevant geworden, da sich die referenzierte Webseite geändert hat

Die Webseite, auf die Sie verweisen, war fehlerhaft. Es wurde an diesem Tag viel bearbeitet und verschiedene Teile waren nicht synchron. Der Status, als ich es betrachtete, war:

Oben auf der Seite werden die aktuell vorhandenen Vergleichsoperatoren (in C ++ 14) aufgelistet. Da ist kein <=>da.

Am Ende der Seite hätten sie dieselben Operatoren auflisten sollen, aber sie haben diesen zukünftigen Vorschlag vermasselt und hinzugefügt.

gccweiß noch nichts darüber <=>(und mit -std=c++14, wird es nie tun), also denkt es, dass du es gemeint hast a <= > b. Dies erklärt die Fehlermeldung.

Wenn Sie in fünf Jahren dasselbe versuchen, erhalten Sie wahrscheinlich eine bessere Fehlermeldung, etwa <=> not part of C++14.


1
Die Webseite, auf die OP verweist, ist korrekt, ebenso wie die separate Seite, auf die Sie verlinken. Es qualifiziert den <=>Operator mit dem Label (seit C ++ 20) und gibt an, in welcher Version des Standards es zu erwarten ist. Die Standardkennzeichnung ist eine Konvention, der cppreference.com folgt. Natürlich haben Sie keinen Compiler, der in einer Zeitmaschine zurückgekommen ist, um ihn für Sie zu unterstützen, aber cpprefernce sagt Ihnen (richtig), was Sie erwartet.
Spencer

Ja, aber ... keine Antwort. Sie kommentieren ... oder so.
qlp

2
Ich wollte auf dieselbe Webseite wie die Frage verlinken, habe sie aber verpasst. Ich glaube, ich habe die Teile der Frage beantwortet, die andere Antworten nicht beantwortet haben. Ich ignorierte die fettgedruckte Hauptfrage, da andere diese bereits beantwortet hatten.
Stig Hemmer
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.