c++ - relacionales - ¿En qué se diferencia el operador de comparación de tres vías de la resta?
operadores relacionales en c++ (3)
Hay un nuevo operador de comparación
<=>
en C ++ 20.
Sin embargo, creo que en la mayoría de los casos una resta simple funciona bien:
int my_strcmp(const char *a, const char *b) {
while (*a == *b && *a != 0 && *b != 0) {
a++, b++;
}
// Version 1
return *a - *b;
// Version 2
return *a <=> *b;
// Version 3
return ((*a > *b) - (*a < *b));
}
Tienen el mismo efecto. Realmente no puedo entender la diferencia.
Aquí hay algunas respuestas significativas sobre la diferencia, pero Herb Sutter en su artículo dice específicamente:
<=> es para implementadores de tipos: el código de usuario (incluido el código genérico) fuera de la implementación de un operador <=> casi nunca debería invocar un <=> directamente (como ya se descubrió como una buena práctica en otros idiomas);
Entonces, incluso si no hubiera diferencia, el punto del operador es diferente: ayudar a los escritores de clases a generar operadores de comparación.
La diferencia principal entre el operador de resta y el operador de "nave espacial" (según la propuesta de Sutter) es que el
operator-
sobrecarga le proporciona un operador de resta, mientras que el
operator<=>
sobrecarga
operator<=>
:
-
le proporciona los 6 operadores de comparación principales (incluso si declara el operador como
default
: ¡no hay código para escribir!); - declara si su clase es comparable, ordenable y si el orden es total o parcial (fuerte / débil en la propuesta de Sutter);
- permite comparaciones heterogéneas: puede sobrecargarlo para comparar su clase con cualquier otro tipo.
Otras diferencias están en el valor de retorno: el
operator<=>
devolvería una
enum
de una clase, la clase especifica si el tipo es ordenable y si el tipo es fuerte o débil.
El valor de retorno se convertiría en -1, 0 o 1 (aunque Sutter deja espacio para que el tipo de retorno también indique la distancia, como
strcmp
hace
strcmp
).
En cualquier caso, suponiendo el valor de retorno -1, 0, 1, ¡finalmente obtendremos
una verdadera función de signum en C ++
!
(
signum(x) == x<=>0
)
Aquí hay algunos casos en los que la resta no funcionará:
-
tipos
unsigned
. - Operandos que causan desbordamiento de enteros.
-
Tipos definidos por el usuario que no definen
operator -
(tal vez porque no tiene sentido, uno puede definir un orden sin definir una noción de distancia).
Sospecho que esta lista no es exhaustiva.
Por supuesto, uno puede encontrar soluciones para al menos # 1 y # 2.
Pero la intención del
operator <=>
es encapsular esa fealdad.
El operador resuelve el problema con el desbordamiento numérico que obtiene con la resta: si resta un número positivo grande de un negativo que está cerca de
INT_MIN
, obtiene un número que no puede representarse como un
int
, lo que provoca un comportamiento indefinido.
Aunque la versión 3 está libre de este problema, carece por completo de legibilidad: tomaría algún tiempo entenderlo por alguien que nunca ha visto este truco antes.
<=>
operador
<=>
soluciona el problema de legibilidad.
Este es solo un problema abordado por el nuevo operador.
La sección 2.2.3 del
documento de
comparación consistente
de
Herb Sutter
habla sobre el uso de
<=>
con otros tipos de datos del lenguaje donde la resta puede producir resultados inconsistentes.