Default comparisons (since C++20)
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:
-
Es una
función miembro no estática
o
amiga
de alguna clase
C. -
Está
definida como predeterminada
en
Co en un contexto dondeCestá completa . -
Tiene dos parámetros de tipo
const
C
&
o dos parámetros de tipo
C, donde el parámetro de objeto implícito (si existe) se considera como el primer parámetro.
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:
- Sea n el número de subobjetos en la lista (expandida) de subobjetos para x .
- Sea x_i el i -ésimo subobjeto en la lista (expandida) de subobjetos para x , donde x_i se forma mediante una secuencia de conversiones de derivado-a-base , expresiones de acceso a miembros de clase , y expresiones de subíndice de array aplicadas a x .
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
Tusandostatic_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.
-
Tno 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.
-
De lo contrario, si
Tes std::strong_ordering , la comparación sintetizada es
a == b ? std::strong_ordering::equal : a < b ? std::strong_ordering::less : std::strong_ordering::greater
-
De lo contrario, si
Tes std::weak_ordering , la comparación sintetizada es
a == b ? std::weak_ordering::equivalent : a < b ? std::weak_ordering::less : std::weak_ordering::greater
-
En caso contrario (
Tes std::partial_ordering ), la comparación sintetizada es
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 :
- 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.
-
Denote la versión sin calificadores cv del tipo de
x_i
<=>
x_i
como
R_i; siR_ino 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:
- El identificador del declarador se reemplaza con operator == .
- El tipo de retorno se reemplaza con bool .
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
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
- resolución de sobrecarga en una llamada a un operador sobrecargado
- Operador de comparación de tres vías incorporado
- Sobrecarga de operadores para operadores de comparación