Namespaces
Variants

Default comparisons (since C++20)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Vergleichsoperatorfunktionen können explizit als Standard festgelegt werden, um den Compiler zu veranlassen, die entsprechende Standardvergleichsfunktion für eine Klasse zu generieren.

Inhaltsverzeichnis

Definition

Eine defaulted comparison operator function ist eine Nicht-Template-Vergleichsoperatorfunktion (d.h. <=> , == , != , < , > , <= , oder >= ), die alle folgenden Bedingungen erfüllt:

Eine solche Vergleichsoperatorfunktion wird als standardmäßige Vergleichsoperatorfunktion für Klasse C bezeichnet.

struct X
{
    bool operator==(const X&) const = default; // OK
    bool operator==(const X&) = default;       // Fehler: Der implizite Objekt-
                                               //        parameter-Typ ist X&
    bool operator==(this X, X) = default;      // OK
};
struct Y
{
    friend bool operator==(Y, Y) = default;        // OK
    friend bool operator==(Y, const Y&) = default; // Fehler: Unterschiedliche Parametertypen
};
bool operator==(const Y&, const Y&) = default;     // Fehler: Kein Freund von Y

Namensauflösungen und Zugriffsprüfungen in der impliziten Definition einer Vergleichsoperatorfunktion werden aus einem Kontext durchgeführt, der ihrem Funktionsrumpf entspricht. Eine Definition einer Vergleichsoperatorfunktion als defaulted, die in einer Klasse erscheint, muss die erste Deklaration dieser Funktion sein.

Standardmäßige Vergleichsreihenfolge

Gegeben eine Klasse C , wird eine Unterobjektliste durch die folgenden Unterobjekte in dieser Reihenfolge gebildet:

  • Die direkten Basisklassen-Subobjekte von C , in Deklarationsreihenfolge.
  • Die nicht-statischen Datenelemente von C , in Deklarationsreihenfolge.
  • Wenn ein beliebiges Mitgliedssubobjekt vom Array-Typ ist, wird es zur Sequenz seiner Elemente erweitert, in der Reihenfolge steigender Indizes. Die Erweiterung ist rekursiv: Array-Elemente von Array-Typen werden erneut erweitert, bis kein Subobjekt mehr vom Array-Typ vorhanden ist.

Für jedes Objekt x vom Typ C gelten in den folgenden Beschreibungen:

struct S {};
struct T : S
{
    int arr[2][2];
} t;
// Die Unterobjektliste für "t" besteht aus den folgenden 5 Unterobjekten in dieser Reihenfolge:
// (S)t → t[0][0] → t[0][1] → t[1][0] → t[1][1]

Dreifachvergleich

Ein operator <=> für einen Klassentyp kann als standardmäßig mit jedem Rückgabetyp definiert werden.

Vergleichskategorien-Typen

Es gibt drei Vergleichskategorien-Typen:

Typ Äquivalente Werte sind.. Unvergleichbare Werte sind..
std::strong_ordering ununterscheidbar nicht erlaubt
std::weak_ordering unterscheidbar nicht erlaubt
std::partial_ordering unterscheidbar erlaubt

Synthetisierter Drei-Wege-Vergleich

Der synthetisierte Drei-Wege-Vergleich vom Typ T zwischen Glvalues a und b desselben Typs wird wie folgt definiert:

  • Wenn die Überladungsauflösung für a <=> b einen verwendbaren Kandidaten ergibt und explizit zu T mittels static_cast konvertiert werden kann, ist der synthetisierte Vergleich static_cast < T > ( a <=> b ) .
  • Andernfalls, wenn eine der folgenden Bedingungen erfüllt ist, ist der synthetisierte Vergleich nicht definiert:
  • Die Überladungsauflösung für a <=> b findet mindestens einen brauchbaren Kandidaten.
  • T ist kein Vergleichskategorientyp.
  • Die Überladungsauflösung für a == b ergibt keinen verwendbaren Kandidaten.
  • Die Überladungsauflösung für a < b ergibt keinen verwendbaren Kandidaten.
a == b ? std::strong_ordering::equal :
a < b  ? std::strong_ordering::less :
         std::strong_ordering::greater
a == b ? std::weak_ordering::equivalent :
a < b  ? std::weak_ordering::less :
         std::weak_ordering::greater
a == b ? std::partial_ordering::equivalent :
a < b  ? std::partial_ordering::less :
b < a  ? std::partial_ordering::greater : 
         std::partial_ordering::unordered

Platzhalter-Rückgabetyp

Wenn der deklarierte Rückgabetyp einer defaulted Drei-Wege-Vergleichsoperator-Funktion ( operator <=> ) für einen Klassentyp C als auto angegeben ist, wird der Rückgabetyp aus den Rückgabetypen der Drei-Wege-Vergleiche zwischen den entsprechenden Unterobjekten eines Objekts x vom Typ C abgeleitet.

Für jedes Unterobjekt x_i in der (erweiterten) Unterobjektliste für x :

  1. Führe Überladungsauflösung für x_i <=> x_i durch. Wenn die Überladungsauflösung keinen verwendbaren Kandidaten ergibt, wird der standardmäßige operator <=> als gelöscht definiert.
  2. Bezeichne die cv-unqualifizierte Version des Typs von x_i <=> x_i als R_i . Wenn R_i kein Vergleichskategorientyp ist, wird der standardmäßige operator <=> als gelöscht definiert.

Wenn der standardmäßig definierte operator <=> nicht als gelöscht definiert ist, wird sein Rückgabetyp als std:: common_comparison_category_t < R_1, R_2, ..., R_n > abgeleitet.

Nicht-Platzhalter-Rückgabetyp

Wenn der deklarierte Rückgabetyp des standardmäßigen operator <=> nicht auto ist, darf er keinen Platzhaltertyp enthalten (z.B. decltype ( auto ) ).

Wenn es ein Unterobjekt x_i in der (erweiterten) Unterobjektliste für x gibt, sodass der synthetisierte Drei-Wege-Vergleich des deklarierten Rückgabetyps zwischen x_i und x_i nicht definiert ist, wird der standardmäßig implementierte operator <=> als gelöscht definiert.

Vergleichsergebnis

Seien x und y die Parameter eines standardmäßigen operator <=> , bezeichnet jedes Unterobjekt in der (erweiterten) Unterobjektliste für x und y als x_i bzw. y_i . Der standardmäßige Drei-Wege-Vergleich zwischen x und y wird durchgeführt, indem entsprechende Unterobjekte x_i und y_i in aufsteigender i -Reihenfolge verglichen werden.

Sei R der (möglicherweise abgeleitete) Rückgabetyp, das Vergleichsergebnis zwischen x_i und y_i ist das Ergebnis des synthetisierten Drei-Wege-Vergleichs vom Typ R zwischen x_i und y_i .

  • Während des standardmäßigen Drei-Wege-Vergleichs zwischen x und y , falls ein teilobjektweiser Vergleich zwischen x_i und y_i ein Ergebnis v_i erzeugt, bei dem die kontextuelle Konvertierung von v_i ! = 0 zu bool true ergibt, ist der Rückgabewert eine Kopie von v_i (die verbleibenden Teilobjekte werden nicht verglichen).
  • Andernfalls ist der Rückgabewert static_cast < R > ( std :: strong_ordering :: equal ) .
#include <compare>
#include <iostream>
#include <set>
struct Point
{
    int x;
    int y;
    auto operator<=>(const Point&) const = default;
    /* non-comparison functions */
};
int main()
{
    Point pt1{1, 1}, pt2{1, 2};
    std::set<Point> s; // OK
    s.insert(pt1);     // OK
    // Zwei-Wege-Vergleichsoperatoren müssen nicht explizit definiert werden:
    // operator== wird implizit deklariert (siehe unten)
    // die Überladungsauflösung anderer Kandidaten wird umgeschriebene Kandidaten auswählen
    std::cout << std::boolalpha
        << (pt1 == pt2) << ' '  // false
        << (pt1 != pt2) << ' '  // true
        << (pt1 <  pt2) << ' '  // true
        << (pt1 <= pt2) << ' '  // true
        << (pt1 >  pt2) << ' '  // false
        << (pt1 >= pt2) << ' '; // false
}

Gleichheitsvergleich

Explizite Deklaration

Ein operator == für einen Klassentyp kann als standardmäßig mit Rückgabetyp bool definiert werden.

Gegeben eine Klasse C und ein Objekt x vom Typ C , falls es ein Unterobjekt x_i in der (erweiterten) Unterobjektliste für x gibt, sodass die Überladungsauflösung für x_i == x_i nicht zu einem verwendbaren Kandidaten führt, wird der standardmäßig implementierte operator == als gelöscht definiert.

Seien x und y die Parameter eines standardmäßigen operator == , bezeichnet jedes Unterobjekt in der (erweiterten) Unterobjektliste für x und y als x_i bzw. y_i . Der standardmäßige Gleichheitsvergleich zwischen x und y wird durchgeführt, indem entsprechende Unterobjekte x_i und y_i in aufsteigender i -Reihenfolge verglichen werden.

Das Vergleichsergebnis zwischen x_i und y_i ist das Ergebnis von x_i == y_i .

  • Während des standardmäßigen Gleichheitsvergleichs zwischen x und y , falls ein subobjektweiser Vergleich zwischen x_i und y_i ein Ergebnis v_i erzeugt, sodass die kontextuelle Konvertierung von v_i zu bool false ergibt, ist der Rückgabewert false (die verbleibenden Subobjekte werden nicht verglichen).
  • Andernfalls ist der Rückgabewert true .
#include <iostream>
struct Point
{
    int x;
    int y;
    bool operator==(const Point&) const = default;
    /* non-comparison functions */
};
int main()
{
    Point pt1{3, 5}, pt2{2, 5};
    std::cout << std::boolalpha
        << (pt1 != pt2) << '\n'  // true
        << (pt1 == pt1) << '\n'; // true
    struct [[maybe_unused]] { int x{}, y{}; } p, q;
    // if (p == q) {} // Error: operator== is not defined
}

Implizite Deklaration

Wenn eine Klasse C keinen Member oder Friend namens operator == explizit deklariert, wird für jeden als default definierten operator <=> implizit eine == -Operatorfunktion deklariert. Jeder implizit deklarierte operator == hat denselben Zugriff und dieselbe Funktionsdefinition sowie denselben Klassenbereich wie der jeweilige default-definierte operator <=> , mit folgenden Änderungen:

template<typename T>
struct X
{
    friend constexpr std::partial_ordering operator<=>(X, X)
        requires (sizeof(T) != 1) = default;
    // deklariert implizit: friend constexpr bool operator==(X, X)
    //                          requires (sizeof(T) != 1) = default;
    [[nodiscard]] virtual std::strong_ordering operator<=>(const X&) const = default;
    // deklariert implizit: [[nodiscard]] virtual bool
    //                          operator==(const X&) const = default;
};

Sekundärer Vergleich

Eine sekundäre Vergleichsoperatorfunktion ( != , < , > , <= , oder >= ) für einen Klassentyp kann als standarddefiniert mit Rückgabetyp bool definiert werden.

Sei @ einer der fünf sekundären Vergleichsoperatoren. Für jeden standardmäßig bereitgestellten operator@ mit Parametern x und y werden bis zu zwei Überladungsauflösungen durchgeführt (ohne den standardmäßigen operator@ als Kandidat zu betrachten), um zu bestimmen, ob er als gelöscht definiert ist.

  • Die erste Überladungsauflösung wird für x @ y durchgeführt. Wenn die Überladungsauflösung nicht zu einem verwendbaren Kandidaten führt oder der ausgewählte Kandidat kein umgeschriebener Kandidat ist, wird der standardmäßige operator@ als gelöscht definiert. In diesen Fällen gibt es keine zweite Überladungsauflösung.
  • Die zweite Überladungsauflösung wird für den ausgewählten umgeschriebenen Kandidaten von x @ y durchgeführt. Wenn die Überladungsauflösung nicht zu einem verwendbaren Kandidaten führt, wird der standardmäßige operator@ als gelöscht definiert.

Wenn x @ y nicht implizit zu bool konvertiert werden kann, ist der standardmäßige operator@ als gelöscht definiert.

Wenn der standardmäßig bereitgestellte operator@ nicht als gelöscht definiert ist, ergibt er x @ y .

struct HasNoRelational {};
struct C
{
    friend HasNoRelational operator<=>(const C&, const C&);
    bool operator<(const C&) const = default; // OK, Funktion ist standardmäßig implementiert
};

Schlüsselwörter

default

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
CWG 2539 C++20 der synthetisierte Drei-Wege-Vergleich würde
static_cast wählen, selbst wenn die explizite Konvertierung nicht verfügbar ist
wählt in diesem Fall nicht
static_cast
CWG 2546 C++20 der standardmäßige sekundäre operator@ wurde nicht
als gelöscht definiert, wenn die Überladungsauflösung von
x @ y einen nicht verwendbaren umgeschriebenen Kandidaten auswählt
in diesem Fall als gelöscht
definiert
CWG 2547 C++20 es war unklar, ob Vergleichsoperator-
funktionen für Nicht-Klassen standardmäßig definiert werden können
sie können nicht standardmäßig definiert werden
CWG 2568 C++20 die implizite Definition von Vergleichsoperator-
funktionen könnte Mitgliedszugriffsregeln verletzen
Zugriffsprüfungen werden
aus einem Kontext durchgeführt,
der ihren Funktionsrumpf entspricht

Siehe auch