Comparaciones por defecto (desde C++20)
Provee un medio para solicitarle al compilador que genere operadores relacionales consistentes para una clase.
Contenido |
[editar] Sintaxis
return-type class-name::operator op( const class-name & ) const & (opcional) = default;
|
(1) | ||||||||
friend return-type operator op( const class-name & , const class-name & ) = default;
|
(2) | ||||||||
friend return-type operator op( class-name, class-name ) = default;
|
(3) | ||||||||
op | - | un operador de comparación (<=> , == , != , < , > , <= , or >= )
|
return-type | - | tipo de retorno de la función. Debe ser:
|
[editar] Explicación
You can help to correct and verify the translation. Click here for instructions.
You can help to correct and verify the translation. Click here for instructions.
You can help to correct and verify the translation. Click here for instructions.
<
, >
, <=
, >=
, o <=>
y la resolución de sobrecargas selecciona esta sobrecarga.<
, >
, <=
, >=
, or <=>
and overload resolution selects this overload.You can help to correct and verify the translation. Click here for instructions.
==
o !=
y la resolución de sobrecargas selecciona esta sobrecarga.==
or !=
and overload resolution selects this overload.You can help to correct and verify the translation. Click here for instructions.
You can help to correct and verify the translation. Click here for instructions.
[editar] Comparaciones predeterminadas
[editar] Comparación de tres vías marcada como predeterminada
You can help to correct and verify the translation. Click here for instructions.
for /*cada subobjeto base o miembro o de T */ if (auto cmp = static_cast<R>(compare(lhs.o, rhs.o)); cmp != 0) return cmp; return static_cast<R>(strong_ordering::equal);
You can help to correct and verify the translation. Click here for instructions.
You can help to correct and verify the translation. Click here for instructions.
template<class T1, class T2> struct P { T1 x1; T2 x2; friend auto operator<=>(const P&, const P&) = default; };
You can help to correct and verify the translation. Click here for instructions.
- Si a <=> b es usable, el resultado de la comparacióńn es static_cast<R>(a <=> b).Original:If a <=> b is usable, the result of comparison is static_cast<R>(a <=> b).The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions. - De lo contrario, si se realiza la resolución de sobrecarga de operator<=> para a<=>b y se encuentra al menos un candidato, la comparación queda como no definida (
operador<=>
se define como eliminado).Original:Otherwise, if overload resolution for operator<=> is performed for a <=> b and at least one candidate is found, the comparison is not defined (operator<=>
is defined as deleted).The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions. - De lo contrario, si R no es un tipo de categoría de comparación (ver más abajo), o bien a==b o a<b no es usable, la comparación queda como no definida (
operator<=>
se define como eliminado).Original:Otherwise, if R is not a comparison category type (see below), or either a == b or a < b is not usable, the comparison is not defined (operator<=>
is defined as deleted).The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions. - De lo contrario, si R es std::strong_ordering el resultado es:Original:Otherwise, if R is std::strong_ordering, the result isThe text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
a == b ? R::equal : a < b ? R::less : R::greater
- De lo contrario, si R es std::weak_ordering, el resultado esOriginal:Otherwise, if R is std::weak_ordering, the result isThe text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
a == b ? R::equivalent : a < b ? R::less : R::greater
- De lo contrario (R es std::partial_ordering), el resultado esOriginal:Otherwise (R is std::partial_ordering), the result isThe text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
a == b ? R::equal : a < b ? R::less : b < a ? R::greater : R::unordered
Según las reglas para cualquier sobrecarga del operator<=>, una sobrecarga predeterminada de <=> también permitirá que el tipo se compare con <, <=, >, y >=.
You can help to correct and verify the translation. Click here for instructions.
#include <compare> struct Point { int x; int y; auto operator<=>(const Point&) const = default; // ... otras funciones que no son de comparación ... }; // el compilador genera todos los seis operadores relacionales #include <iostream> #include <set> int main() { Point pt1{1, 1}, pt2{1, 2}; std::set<Point> s; // ok s.insert(pt1); // ok std::cout << std::boolalpha << (pt1 == pt2) << ' ' // false; operator== es implicitamente predeterminado. << (pt1 != pt2) << ' ' // true << (pt1 < pt2) << ' ' // true << (pt1 <= pt2) << ' ' // true << (pt1 > pt2) << ' ' // false << (pt1 >= pt2) << ' ';// false }
[editar] Comparación de igualdad marcado como predeterminado
Una clase puede definir el operador operator== como predeterminado, con un valor de retorno bool. Esto generará una comparación de igualdad para cada clase base y sub-objeto miembro, de acuerdo con su orden de declaración. Dos objetos son iguales si los valores de sus miembros y de sus clases base son iguales. La evaluación hará corto circuito si encuentra una diferencia en miembros o en clases base según su orden de declaración.
De acuerdo con las reglas para el operator==, esto también permite evaluar diferencia !=:
struct Point { int x; int y; bool operator==(const Point&) const = default; // ... otras funciones que no son de comparación ... }; // el compilador genera evaluaciones de igualdad por elemento #include <iostream> 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==' no está definido }
[editar] Otros operadores de comparación marcados como predeterminados
Cualquiera de los otros cuatro operadores relacionales puede ser marcado explícitamente como predeterminado. Su tipo de retorno deberá ser bool.
Dicho operador se marcará como borrado si falla la resolución de sobrecarga sobre x<=>y (considerando también el operator<=> con orden inverso de parámetros), o si el operator@ no es aplicable al resultado de esa x<=>y. De lo contrario, el operator@ predeterminado llama a x<=>y @ 0 si se seleccionó un operador <=> con el orden original de los parámetros por resolución de sobrecarga, o 0 @ y<=>x de lo contrario:
struct HasNoRelational {}; struct C { friend HasNoRelational operator<=>(const C&, const C&); bool operator<(const C&) = default; // ok, la función es borrada };
De manera similar, el operator!= puede marcarse como predeterminado. Se marca como borrado si falla la resolución de sobrecarga sobre x==y (considerando también el operator== con orden inverso de parámetros) falla, o si el resultado de x==y no tiene el tipo bool. El operator!= predeterminado llama a !(x==y) o !(y==x) según lo seleccionado por la resolución de sobrecarga.
Marcar operadores relacionales como predeterminados puede ser útil para crear funciones cuyas direcciones pueden ser tomadas. Para otros usos, es suficiente proporcionar solo operator<=> y operator==.
[editar] Comparaciones personalizadas y categorías de comparación
Cuando las semánticas predeterminadas no son adecuadas, por ejemplo cuando los miembros deban ser comparados en desorden, o cuando deban usar una comparación que es diferente de su comparación natural, el programador puede definir el operador operator<=> y dejar que el compilador genere los operadores relacionales apropiados. Los tipos de operadores relacionales generados dependen del tipo de retorno del operator<=> definido por el usuario.
Hay tres tipos de retorno disponibles:
Tipo de retorno | Operadores | Valores equivalentes son | Valores no comparables son |
---|---|---|---|
std::strong_ordering | == != < > <= >= | indistinguibles | no permitidos |
std::weak_ordering | == != < > <= >= | distinguibles | no permitidos |
std::partial_ordering | == != < > <= >= | distinguibles | permitidos |
[editar] Ordenamiento fuerte
Un ejemplo de un operator<=> personalizado que retorna std::strong_ordering es uno que compara cada miembro de una clase en un orden diferente al predeterminado (ordenar por last_name)
#include <compare> #include <string> struct Base { std::string zip; auto operator<=>(const Base&) const = default; }; struct TotallyOrdered : Base { std::string tax_id; std::string first_name; std::string last_name; public: // operator<=> personalizado para ordenar por last_name: std::strong_ordering operator<=>(const TotallyOrdered& that) const { if (auto cmp = (Base&)(*this) <=> (Base&)that; cmp != 0) return cmp; if (auto cmp = last_name <=> that.last_name; cmp != 0) return cmp; if (auto cmp = first_name <=> that.first_name; cmp != 0) return cmp; return tax_id <=> that.tax_id; } // ... otras funciones que no son de comparación ... }; // el compilador genera todos los operadores relacionales #include <cassert> #include <set> int main() { TotallyOrdered to1{"a","b","c","d"}, to2{"a","b","d","c"}; std::set<TotallyOrdered> s; // ok s.insert(to1); // ok assert(to2 <= to1); // ok, una sola llamada a <=> }
You can help to correct and verify the translation. Click here for instructions.
[editar] Ordenamiento débil
Un ejemplo de un operator<=> personalizado que retorna std::weak_ordering es uno que compara cada miembro string de una clase de una manera que no distingue entre mayúsculas y minúsculas; esto es diferente de la comparación predeterminada (requiere un operador personalizado) y es posible distinguir dos cadenas que comparan a igualdad:
class CaseInsensitiveString { std::string s; public: std::weak_ordering operator<=>(const CaseInsensitiveString& b) const { return case_insensitive_compare(s.c_str(), b.s.c_str()); } std::weak_ordering operator<=>(const char* b) const { return case_insensitive_compare(s.c_str(), b); } // ... otras funciones que no son de comparación ... }; // el compilador genera todos los operadores relacionales CaseInsensitiveString cis1, cis2; std::set<CaseInsensitiveString> s; // ok s.insert(/*...*/); // ok if (cis1 <= cis2) { /*...*/ } // ok, realiza una operación de comparación // El compilador también genera todos los ocho operadores relacionales heterogéneos if (cis1 <= "xyzzy") { /*...*/ } // ok, realiza una operación de comparación if ("xyzzy" >= cis1) { /*...*/ } // ok, semántica identica
Nota: Este ejemplo demuestra el efecto del operador heterogéneo operator<=>, genera comparaciones heterogéneas en ambas direcciones.
[editar] Ordenamiento parcial
Este ordenamiento es aquel que permite valores no comparables (desordenados), tales como valores NaN en ordenamientos de punto flotante; en este ejemplo, personas que no son familiares:
class PersonInFamilyTree { // ... public: std::partial_ordering operator<=>(const PersonInFamilyTree& that) const { if (this->is_the_same_person_as ( that)) return partial_ordering::equivalent; if (this->is_transitive_child_of( that)) return partial_ordering::less; if (that. is_transitive_child_of(*this)) return partial_ordering::greater; return partial_ordering::unordered; } // ... otras funciones que no son de comparación ... }; // el compilador genera todos los operadores relacionales PersonInFamilyTree per1, per2; if (per1 < per2) { /*...*/ } // ok, per2 es un ancestro de per1 else if (per1 > per2) { /*...*/ } // ok, per1 es un ancestro de per2 else if (std::is_eq(per1 <=> per2)) { /*...*/ } // ok, per1 es per2 else { /*...*/ } // per1 y per2 no son familiares if (per1 <= per2) { /*...*/ } // ok, per2 es per1 o es un ancestro de per1 if (per1 >= per2) { /*...*/ } // ok, per1 es per2 o es un ancestro de per2 if (std::is_neq(per1 <=> per2)) { /*...*/ } // ok, per1 no es per2
[editar] Ver 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 relacionales