c++ c++20 spaceship-operator

El operador de igualdad no se define para una implementación de operador de nave espacial personalizada en C++ 20



c++20 spaceship-operator (3)

Durante la estandarización de esta característica, se decidió que la igualdad y el orden deberían estar separados lógicamente. Como tal, los usos de las pruebas de igualdad ( == y != ) Nunca invocarán al operator<=> . Sin embargo, todavía se consideró útil poder predeterminarlos con una sola declaración. Entonces, si su operator<=> predeterminado es operator<=> , se decidió que también tenía la intención de hacerlo por defecto operator== (a menos que lo defina más adelante o lo haya definido antes).

En cuanto a por qué se tomó esta decisión , el razonamiento básico es el siguiente. Considere std::string . El pedido de dos cadenas es lexicográfico; cada carácter tiene su valor entero comparado con cada carácter en la otra cadena. La primera desigualdad resulta en el resultado de ordenar.

Sin embargo, la prueba de igualdad de cadenas tiene un cortocircuito. Si las dos cadenas no tienen la misma longitud, entonces no tiene sentido hacer una comparación entre caracteres; No son iguales. Entonces, si alguien está haciendo pruebas de igualdad, no querrá hacerlo de forma larga si puede hacer un corto circuito.

Resulta que muchos tipos que necesitan un pedido definido por el usuario también ofrecerán algún mecanismo de cortocircuito para las pruebas de igualdad. Para evitar que las personas implementen solo el operator<=> y desechen el rendimiento potencial, efectivamente obligamos a todos a hacer ambas cosas.

Me encuentro con un comportamiento extraño con el nuevo operador de nave espacial <=> en C ++ 20. Estoy usando el compilador de Visual Studio 2019 con /std:c++latest .

Este código se compila bien, como se esperaba:

#include <compare> struct X { int Dummy = 0; auto operator<=>(const X&) const = default; // Default implementation }; int main() { X a, b; a == b; // OK! return 0; }

Sin embargo, si cambio X a esto:

struct X { int Dummy = 0; auto operator<=>(const X& other) const { return Dummy <=> other.Dummy; } };

Me sale el siguiente error del compilador:

error C2676: binary ''=='': ''X'' does not define this operator or a conversion to a type acceptable to the predefined operator

Intenté esto también en clang, y tengo un comportamiento similar.

Agradecería alguna explicación sobre por qué la implementación predeterminada genera el operator== correctamente, pero la personalizada no.


Esto es por diseño.

[class.compare.default] (énfasis mío)

3 Si la definición de clase no declara explícitamente una función de operador == , pero declara una función de operador de comparación tripartita predeterminada , una función de operador == se declara implícitamente con el mismo acceso que la función de operador de comparación tridireccional. El operador == declarado implícitamente para una clase X es un miembro en línea y se define como predeterminado en la definición de X.

Solo un <=> defecto permitirá que exista un == sintetizado. La razón es clases como std::vector . Obviamente no puede usar un <=> predeterminado. Y resulta que conectar <=> for == al comparar vectores no es la forma más eficiente de compararlos. <=> debe dar el orden exacto, mientras que == puede salir temprano comparando tamaños primero.

Si una clase hace algo especial en su comparación tripartita, es más que probable que deba hacer algo especial en su == . Entonces, en lugar de generar un valor predeterminado no sensible, el lenguaje lo deja al programador.


Las otras respuestas explican muy bien por qué el lenguaje es así. Solo quería agregar que en caso de que no sea obvio, es posible tener un operator<=> proporcionado por el usuario operator<=> con un operator== predeterminado operator== . Solo necesita escribir explícitamente el operator== predeterminado operator== :

struct X { int Dummy = 0; auto operator<=>(const X& other) const { return Dummy <=> other.Dummy; } bool operator==(const X& other) const = default; };