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

Las funciones de operador de comparación pueden ser explícitamente defaulted para solicitar al compilador que genere la comparación predeterminada correspondiente para una clase.

Contenidos

Definición

Una función de operador de comparación predeterminada es una función de operador de comparación no plantilla (es decir, <=> , == , != , < , > , <= , o >= ) que satisface todas las siguientes condiciones:

Tal función de operador de comparación se denomina función de operador de comparación predeterminada para la clase C .

struct X
{
    bool operator==(const X&) const = default; // Correcto
    bool operator==(const X&) = default;       // Error: el tipo del parámetro de objeto implícito
                                               //        es X&
    bool operator==(this X, X) = default;      // Correcto
};
struct Y
{
    friend bool operator==(Y, Y) = default;        // Correcto
    friend bool operator==(Y, const Y&) = default; // Error: tipos de parámetros diferentes
};
bool operator==(const Y&, const Y&) = default;     // Error: no es amigo de Y

Las búsquedas de nombres y las comprobaciones de acceso en la definición implícita de una función de operador de comparación se realizan desde un contexto equivalente a su cuerpo de función. Una definición de una función de operador de comparación como predeterminada que aparece en una clase debe ser la primera declaración de esa función.

Orden de comparación predeterminado

Dada una clase C , una lista de subobjetos se forma por los siguientes subobjetos en orden:

  • Los subobjetos de clase base directa de C , en orden de declaración.
  • Los data members no estáticos de C , en orden de declaración.
  • Si cualquier subobjeto miembro es de tipo array, se expande a la secuencia de sus elementos, en orden de subíndice creciente. La expansión es recursiva: los elementos de array de tipos array se expandirán nuevamente hasta que no queden subobjetos de tipo array.

Para cualquier objeto x de tipo C , en las siguientes descripciones:

struct S {};
struct T : S
{
    int arr[2][2];
} t;
// La lista de subobjetos para "t" consiste en los siguientes 5 subobjetos en orden:
// (S)t → t[0][0] → t[0][1] → t[1][0] → t[1][1]

Comparación de tres vías

Un operator <=> para un tipo de clase puede definirse como predeterminado con cualquier tipo de retorno.

Tipos de categorías de comparación

Hay tres tipos de categorías de comparación:

Tipo Los valores equivalentes son.. Los valores incomparables son..
std::strong_ordering indistinguibles no permitidos
std::weak_ordering distinguibles no permitidos
std::partial_ordering distinguibles permitidos

Comparación de tres vías sintetizada

La comparación sintetizada de tres vías del tipo T entre glvalues a y b del mismo tipo se define de la siguiente manera:

  • Si la resolución de sobrecarga para a <=> b resulta en un candidato usable, y puede ser convertido explícitamente a T usando static_cast , la comparación sintetizada es static_cast < T > ( a <=> b ) .
  • De lo contrario, si se satisface cualquiera de las siguientes condiciones, la comparación sintetizada no está definida:
  • La resolución de sobrecarga para a <=> b encuentra al menos un candidato viable.
  • T no es un tipo de categoría de comparación.
  • La resolución de sobrecarga para a == b no resulta en un candidato utilizable.
  • La resolución de sobrecarga para a < b no resulta en un candidato utilizable.
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

Tipo de retorno de marcador de posición

Si el tipo de retorno declarado de una función de operador de comparación de tres vías por defecto ( operator <=> ) para un tipo de clase C es auto , el tipo de retorno se deduce de los tipos de retorno de las comparaciones de tres vías entre los subobjetos correspondientes de un objeto x de tipo C .

Para cada subobjeto x_i en la lista de subobjetos (expandida) para x :

  1. Realice la resolución de sobrecarga para x_i <=> x_i ; si la resolución de sobrecarga no resulta en un candidato usable, el operator <=> por defecto se define como eliminado.
  2. Denote la versión sin calificadores cv del tipo de x_i <=> x_i como R_i ; si R_i no es un tipo de categoría de comparación, el operator <=> por defecto se define como eliminado.

Si el operador operator <=> por defecto no está definido como eliminado, su tipo de retorno se deduce como std:: common_comparison_category_t < R_1, R_2, ..., R_n > .

Tipo de retorno no-placeholder

Si el tipo de retorno declarado del operador operator <=> por defecto no es auto , no puede contener ningún tipo de marcador de posición (por ejemplo, decltype ( auto ) ).

Si hay un subobjeto x_i en la lista de subobjetos (expandida) para x tal que la comparación de tres vías sintetizada del tipo de retorno declarado entre x_i y x_i no está definida, el operator <=> por defecto se define como eliminado.

Resultado de comparación

Sean x y y los parámetros de un operator <=> con valor por defecto, denótese cada subobjeto en la lista (expandida) de subobjetos para x y y como x_i y y_i respectivamente. La comparación triple por defecto entre x y y se realiza comparando los subobjetos correspondientes x_i y y_i en orden creciente de i .

Sea R el tipo de retorno (posiblemente deducido), el resultado de comparación entre x_i y y_i es el resultado de la comparación de tres vías sintetizada de tipo R entre x_i y y_i .

  • Durante la comparación de tres vías predeterminada entre x y y , si una comparación subobjeto por subobjeto entre x_i y y_i genera un resultado v_i tal que la conversión contextual de v_i ! = 0 a bool produce true , el valor de retorno es una copia de v_i (los subobjetos restantes no serán comparados).
  • De lo contrario, el valor de retorno es 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;
    /* funciones que no son de comparación */
};
int main()
{
    Point pt1{1, 1}, pt2{1, 2};
    std::set<Point> s; // OK
    s.insert(pt1);     // OK
    // no se requiere definir explícitamente las funciones de operador de comparación bidireccional:
    // operator== se declara implícitamente (ver abajo)
    // las resoluciones de sobrecarga de otros candidatos seleccionarán candidatos reescritos
    std::cout << std::boolalpha
        << (pt1 == pt2) << ' '  // false
        << (pt1 != pt2) << ' '  // true
        << (pt1 <  pt2) << ' '  // true
        << (pt1 <= pt2) << ' '  // true
        << (pt1 >  pt2) << ' '  // false
        << (pt1 >= pt2) << ' '; // false
}

Comparación de igualdad

Declaración explícita

Un operator == para un tipo de clase puede definirse como predeterminado con tipo de retorno bool .

Dada una clase C y un objeto x de tipo C , si existe un subobjeto x_i en la lista (expandida) de subobjetos para x tal que la resolución de sobrecarga para x_i == x_i no resulta en un candidato utilizable, el operator == por defecto se define como eliminado.

Sean x y y los parámetros de un operator == por defecto, denótese cada subobjeto en la lista de subobjetos (expandida) para x y y como x_i y y_i respectivamente. La comparación de igualdad por defecto entre x y y se realiza comparando los subobjetos correspondientes x_i y y_i en orden creciente de i .

El resultado de la comparación entre x_i y y_i es el resultado de x_i == y_i .

  • Durante la comparación de igualdad predeterminada entre x y y , si una comparación subobjeto por subobjeto entre x_i y y_i genera un resultado v_i tal que la conversión contextual de v_i a bool produce false , el valor de retorno es false (los subobjetos restantes no se compararán).
  • De lo contrario, el valor de retorno es true .
#include <iostream>
struct Point
{
    int x;
    int y;
    bool operator==(const Point&) const = default;
    /* funciones sin comparación */
};
int main()
{
    Point pt1{3, 5}, pt2{2, 5};
    std::cout << std::boolalpha
        << (pt1 != pt2) << '\n'  // verdadero
        << (pt1 == pt1) << '\n'; // verdadero
    struct [[maybe_unused]] { int x{}, y{}; } p, q;
    // if (p == q) {} // Error: operator== no está definido
}

Declaración implícita

Si una clase C no declara explícitamente ningún miembro o amigo llamado operator == , una función == operator es declarada implícitamente para cada operator <=> definido como predeterminado. Cada operator == declarado implícitamente tiene el mismo acceso y function definition y en el mismo class scope que el respectivo operator <=> predeterminado, con los siguientes cambios:

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

Comparación secundaria

Una función de operador de comparación secundaria ( != , < , > , <= , o >= ) para un tipo de clase puede definirse como predeterminada con tipo de retorno bool .

Sea @ uno de los cinco operadores de comparación secundarios, para cada operator@ predeterminado con parámetros x y y , se realizan hasta dos resoluciones de sobrecarga (sin considerar el operator@ predeterminado como candidato) para determinar si está definido como eliminado.

  • La primera resolución de sobrecarga se realiza para x @ y . Si la resolución de sobrecarga no resulta en un candidato utilizable, o el candidato seleccionado no es un candidato reescrito , el operator@ por defecto se define como eliminado. No hay segunda resolución de sobrecarga en estos casos.
  • La segunda resolución de sobrecarga se realiza para el candidato reescrito seleccionado de x @ y . Si la resolución de sobrecarga no resulta en un candidato utilizable, el operator@ por defecto se define como eliminado.

Si x @ y no puede convertirse implícitamente a bool , el operator@ por defecto se define como eliminado.

Si el operador por defecto operator@ no está definido como eliminado, produce x @ y .

struct HasNoRelational {};
struct C
{
    friend HasNoRelational operator<=>(const C&, const C&);
    bool operator<(const C&) const = default; // OK, la función se establece por defecto
};

Palabras clave

default

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.

DR Aplicado a Comportamiento publicado Comportamiento correcto
CWG 2539 C++20 la comparación de tres vías sintetizada elegiría
static_cast incluso si la conversión explícita no está disponible
no elige
static_cast en este caso
CWG 2546 C++20 el operador secundario por defecto operator@ no estaba
definido como eliminado si la resolución de sobrecarga de
x @ y selecciona un candidato reescrito no utilizable
definido como eliminado
en este caso
CWG 2547 C++20 no estaba claro si las funciones de operadores de comparación
para no-clases pueden tener valores por defecto
no pueden tener valores por defecto
CWG 2568 C++20 la definición implícita de funciones de operadores de comparación
podría violar las reglas de acceso a miembros
se realizan verificaciones de acceso
desde un contexto equivalente
a sus cuerpos de función

Véase también