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

Les fonctions d'opérateur de comparaison peuvent être explicitement définies par défaut pour demander au compilateur de générer la comparaison par défaut correspondante pour une classe.

Table des matières

Définition

Une fonction opérateur de comparaison par défaut est une fonction opérateur de comparaison non template (c'est-à-dire <=> , == , != , < , > , <= , ou >= ) satisfaisant toutes les conditions suivantes :

Une telle fonction d'opérateur de comparaison est appelée une fonction d'opérateur de comparaison par défaut pour la classe C .

struct X
{
    bool operator==(const X&) const = default; // Correct
    bool operator==(const X&) = default;       // Erreur : le type du paramètre objet implicite
                                               //        est X&
    bool operator==(this X, X) = default;      // Correct
};
struct Y
{
    friend bool operator==(Y, Y) = default;        // Correct
    friend bool operator==(Y, const Y&) = default; // Erreur : types de paramètres différents
};
bool operator==(const Y&, const Y&) = default;     // Erreur : pas un ami de Y

Les recherches de nom et les vérifications d'accès dans la définition implicite d'une fonction d'opérateur de comparaison sont effectuées depuis un contexte équivalent à son corps de fonction. Une définition d'une fonction d'opérateur de comparaison comme étant par défaut qui apparaît dans une classe doit être la première déclaration de cette fonction.

Ordre de comparaison par défaut

Étant donné une classe C , une liste de sous-objets est formée par les sous-objets suivants dans l'ordre :

  • Les sous-objets de classe de base directs de C , dans l'ordre de déclaration.
  • Les data members non statiques de C , dans l'ordre de déclaration.
  • Si un quelconque sous-objet membre est de type tableau, il est étendu en la séquence de ses éléments, dans l'ordre des indices croissants. L'extension est récursive : les éléments de tableau de types tableau seront à nouveau étendus jusqu'à ce qu'il n'y ait plus de sous-objet de type tableau.

Pour tout objet x de type C , dans les descriptions suivantes :

struct S {};
struct T : S
{
    int arr[2][2];
} t;
// La liste des sous-objets pour « t » comprend les 5 sous-objets suivants dans l'ordre :
// (S)t → t[0][0] → t[0][1] → t[1][0] → t[1][1]

Comparaison à trois voies

Un opérateur <=> pour un type classe peut être défini comme par défaut avec n'importe quel type de retour.

Types de catégories de comparaison

Il existe trois types de catégories de comparaison :

Type Les valeurs équivalentes sont.. Les valeurs incomparables sont..
std::strong_ordering indiscernables non autorisées
std::weak_ordering discernables non autorisées
std::partial_ordering discernables autorisées

Comparaison à trois voies synthétisée

La comparaison triple synthétisée du type T entre les glvalues a et b de même type est définie comme suit :

  • Si la résolution de surcharge pour a <=> b aboutit à un candidat utilisable, et peut être explicitement converti en T en utilisant static_cast , la comparaison synthétisée est static_cast < T > ( a <=> b ) .
  • Sinon, si l'une des conditions suivantes est satisfaite, la comparaison synthétisée n'est pas définie :
  • La résolution de surcharge pour a <=> b trouve au moins un candidat viable.
  • T n'est pas un type de catégorie de comparaison.
  • La résolution de surcharge pour a == b ne résulte pas en un candidat utilisable.
  • La résolution de surcharge pour a < b ne résulte pas en un candidat utilisable.
a == b ? std::strong_ordering::equal :
a < b  ? std::strong_ordering::less :
         std::strong_ordering::greater
**Note:** Le code C++ n'a pas été traduit conformément aux instructions, car il se trouve dans des balises `
` et contient des termes spécifiques au C++ qui doivent être préservés. Seul le texte environnant (comme ce commentaire) a été traduit en français.
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
**Note:** Le code C++ n'a pas été traduit conformément aux instructions, car il se trouve dans des balises `
` et contient des termes spécifiques au C++ qui doivent être préservés. Seul le texte environnant (s'il y en avait) aurait été traduit en français.

Type de retour générique

Si le type de retour déclaré d'une fonction opérateur de comparaison à trois voies par défaut ( operator <=> ) pour un type de classe C est auto , le type de retour est déduit des types de retour des comparaisons à trois voies entre les sous-objets correspondants d'un objet x de type C .

Pour chaque sous-objet x_i dans la liste des sous-objets (étendue) pour x :

  1. Effectuer la résolution de surcharge pour x_i <=> x_i , si la résolution de surcharge ne produit pas un candidat utilisable, l'opérateur operator <=> par défaut est défini comme supprimé.
  2. Noter la version sans qualificatifs cv du type de x_i <=> x_i comme R_i , si R_i n'est pas un type de catégorie de comparaison, l'opérateur operator <=> par défaut est défini comme supprimé.

Si l'opérateur operator <=> par défaut n'est pas défini comme supprimé, son type de retour est déduit comme std:: common_comparison_category_t < R_1, R_2, ..., R_n > .

Type de retour non-générique

Si le type de retour déclaré de l'opérateur operator <=> par défaut n'est pas auto , il ne peut contenir aucun type substitutif (par exemple decltype ( auto ) ).

S'il existe un sous-objet x_i dans la liste (étendue) des sous-objets pour x tel que la comparaison à trois voies synthétisée du type de retour déclaré entre x_i et x_i n'est pas définie, l'opérateur par défaut operator <=> est défini comme supprimé.

Résultat de comparaison

Soient x et y les paramètres d'un operator <=> par défaut, désignons chaque sous-objet dans la liste (développée) des sous-objets pour x et y comme x_i et y_i respectivement. La comparaison à trois voies par défaut entre x et y est effectuée en comparant les sous-objets correspondants x_i et y_i avec un ordre croissant de i .

Soit R le type de retour (éventuellement déduit), le résultat de la comparaison entre x_i et y_i est le résultat de la comparaison à trois voies synthétisée de type R entre x_i et y_i .

  • Lors de la comparaison à trois voies par défaut entre x et y , si une comparaison sous-objet par sous-objet entre x_i et y_i génère un résultat v_i tel que la conversion contextuelle de v_i ! = 0 en bool donne true , la valeur de retour est une copie de v_i (les sous-objets restants ne seront pas comparés).
  • Sinon, la valeur de retour est 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;
    /* fonctions non-comparaison */
};
int main()
{
    Point pt1{1, 1}, pt2{1, 2};
    std::set<Point> s; // OK
    s.insert(pt1);     // OK
    // les fonctions d'opérateur de comparaison bidirectionnelle ne sont pas requises d'être définies explicitement :
    // operator== est implicitement déclaré (voir ci-dessous)
    // les résolutions de surcharge des autres candidats sélectionneront les candidats réécrits
    std::cout << std::boolalpha
        << (pt1 == pt2) << ' '  // false
        << (pt1 != pt2) << ' '  // true
        << (pt1 <  pt2) << ' '  // true
        << (pt1 <= pt2) << ' '  // true
        << (pt1 >  pt2) << ' '  // false
        << (pt1 >= pt2) << ' '; // false
}

Comparaison d'égalité

Déclaration explicite

Un operator == pour un type classe peut être défini comme étant par défaut avec le type de retour bool .

Étant donné une classe C et un objet x de type C , s'il existe un sous-objet x_i dans la liste (développée) des sous-objets pour x tel que la résolution de surcharge pour x_i == x_i ne résulte pas en un candidat utilisable, l'opérateur operator == par défaut est défini comme supprimé.

Soient x et y les paramètres d'un operator == par défaut, désignons chaque sous-objet dans la liste (développée) de sous-objets pour x et y comme x_i et y_i respectivement. La comparaison d'égalité par défaut entre x et y est effectuée en comparant les sous-objets correspondants x_i et y_i dans l'ordre croissant de i .

Le résultat de la comparaison entre x_i et y_i est le résultat de x_i == y_i .

  • Lors de la comparaison d'égalité par défaut entre x et y , si une comparaison sous-objet par sous-objet entre x_i et y_i génère un résultat v_i tel que la conversion contextuelle de v_i en bool donne false , la valeur de retour est false (les sous-objets restants ne seront pas comparés).
  • Sinon, la valeur de retour est 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
}

Déclaration implicite

Si une classe C ne déclare explicitement aucun membre ou ami nommé operator == , une fonction opérateur == est déclarée implicitement pour chaque operator <=> défini comme étant par défaut. Chaque operator == implicitement déclaré possède le même accès et la même définition de fonction et se trouve dans la même portée de classe que le operator <=> par défaut respectif, avec les modifications suivantes :

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

Comparaison secondaire

Une fonction d'opérateur de comparaison secondaire ( != , < , > , <= , ou >= ) pour un type classe peut être définie comme étant par défaut avec le type de retour bool .

Soit @ l'un des cinq opérateurs de comparaison secondaires, pour chaque operator@ par défaut avec les paramètres x et y , jusqu'à deux résolutions de surcharge sont effectuées (sans considérer le operator@ par défaut comme candidat) pour déterminer s'il est défini comme supprimé.

  • La première résolution de surcharge est effectuée pour x @ y . Si la résolution de surcharge ne résulte pas en un candidat utilisable, ou si le candidat sélectionné n'est pas un candidat réécrit , l'opérateur par défaut operator@ est défini comme supprimé. Il n'y a pas de seconde résolution de surcharge dans ces cas.
  • La seconde résolution de surcharge est effectuée pour le candidat réécrit sélectionné de x @ y . Si la résolution de surcharge ne résulte pas en un candidat utilisable, l'opérateur par défaut operator@ est défini comme supprimé.

Si x @ y ne peut pas être implicitement converti en bool , l'opérateur operator@ par défaut est défini comme supprimé.

Si l'opérateur operator@ par défaut n'est pas défini comme supprimé, il produit x @ y .

struct HasNoRelational {};
struct C
{
    friend HasNoRelational operator<=>(const C&, const C&);
    bool operator<(const C&) const = default; // OK, la fonction est définie par défaut
};

Mots-clés

default

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement publié Comportement corrigé
CWG 2539 C++20 la comparaison à trois voies synthétisée choisirait
static_cast même si la conversion explicite n'est pas disponible
ne choisit pas
static_cast dans ce cas
CWG 2546 C++20 l'opérateur secondaire par défaut operator@ n'était pas
défini comme supprimé si la résolution de surcharge de
x @ y sélectionne un candidat réécrit non utilisable
défini comme supprimé
dans ce cas
CWG 2547 C++20 il n'était pas clair si les fonctions d'opérateur de comparaison
pour les non-classes peuvent être définies par défaut
elles ne peuvent pas être définies par défaut
CWG 2568 C++20 la définition implicite des fonctions d'opérateur de comparaison
pourrait violer les règles d'accès aux membres
les vérifications d'accès sont effectuées
depuis un contexte équivalent
à leurs corps de fonction

Voir aussi