Al comparar dos instancias de la siguiente estructura, recibo un error:
struct MyStruct1 {
MyStruct1(const MyStruct2 &_my_struct_2, const int _an_int = -1) :
my_struct_2(_my_struct_2),
an_int(_an_int)
{}
std::string toString() const;
MyStruct2 my_struct_2;
int an_int;
};
El error es:
error C2678: binario '==': no se encontró un operador que toma un operando de la izquierda del tipo 'myproj :: MyStruct1' (o no hay conversión aceptable)
¿Por qué?
c++
struct
comparison-operators
Jonathan
fuente
fuente
struct
s para la igualdad? Y si desea la forma más sencilla, siempre haymemcmp
tanto tiempo que sus estructuras no contienen puntero.memcmp
falla con miembros que no son POD (comostd::string
) y estructuras acolchadas.==
operador --- con una semántica que casi nunca es la deseada. (Y no proporcionan un medio para anularlo, por lo que termina teniendo que usar una función miembro). Los lenguajes "modernos" que conozco tampoco proporcionan semántica de valor, por lo que estás obligado a usar punteros, incluso cuando no son apropiados.operator=
(incluso si a menudo hace lo incorrecto), por razones de compatibilidad con C.operator==
Sin embargo, la compatibilidad con C no requiere un . Globalmente, prefiero lo que hace C ++ a lo que hace Java. (No sé C #, así que tal vez sea mejor.)= default
!C ++ 20 introdujo comparaciones predeterminadas, también conocidas como "nave espacial"
operator<=>
, que le permite solicitar operadores<
/<=
/==
/!=
/>=
/ y / o>
operadores generados por el compilador con la implementación obvia / ingenua (?) ...... pero puede personalizarlo para situaciones más complicadas (discutidas a continuación). Vea aquí la propuesta de lenguaje, que contiene justificaciones y discusión. Esta respuesta sigue siendo relevante para C ++ 17 y versiones anteriores, y para obtener información sobre cuándo debe personalizar la implementación de
operator<=>
....Puede parecer un poco inútil que C ++ no haya estandarizado esto antes, pero a menudo las estructuras / clases tienen algunos miembros de datos para excluir de la comparación (por ejemplo, contadores, resultados almacenados en caché, capacidad del contenedor, código de éxito / error de la última operación, cursores), como así como decisiones a tomar acerca de innumerables cosas que incluyen, entre otras:
int
miembro en particular podría eliminar el 99% de los objetos desiguales muy rápidamente, mientras que unmap<string,string>
miembro a menudo puede tener entradas idénticas y ser relativamente costoso de comparar - si los valores se cargan en tiempo de ejecución, el programador puede tener información sobre el el compilador no puede posiblementevector
,list
), y si es así, si está bien ordenarlos en el lugar antes de comparar o usar memoria adicional para clasificar los temporales cada vez que se realiza una comparaciónunion
a compararoperator==
sí mismos (pero pueden tenercompare()
ooperator<
ostr()
o captadores ...)Por lo tanto, es bueno tener un error hasta que haya pensado explícitamente en lo que debería significar la comparación para su estructura específica, en lugar de dejar que se compile pero no le dé un resultado significativo en tiempo de ejecución .
Dicho todo esto, sería bueno si C ++ le permitiera decir
bool operator==() const = default;
cuándo decidió que una==
prueba "ingenua" miembro por miembro estaba bien. Lo mismo para!=
. Dadas las múltiples miembros / bases, "por defecto"<
,<=
,>
, y>=
las implementaciones parecen sin esperanza, aunque - en cascada sobre la base de la orden de que todo es posible, pero muy poco probable que sea lo que quería, dado conflictivos imperativos para el pedido miembro (bases de ser necesariamente ante los miembros, la agrupación por declaración accesibilidad, construcción / destrucción antes del uso dependiente). Para ser más útil, C ++ necesitaría un nuevo miembro de datos / sistema de anotación de base para guiar las elecciones; sin embargo, eso sería una gran cosa para tener en el Estándar, idealmente junto con la generación de código definido por el usuario basada en AST ... eso'Implementación típica de operadores de igualdad
Una implementación plausible
Es probable que una implementación razonable y eficiente sea:
Tenga en cuenta que esto necesita una
operator==
paraMyStruct2
también.Las implicaciones de esta implementación y las alternativas se discuten bajo el título Discusión de los detalles de su MyStruct1 a continuación.
Un enfoque coherente para ==, <,> <= etc.
Es fácil aprovechar
std::tuple
los operadores de comparación para comparar sus propias instancias de clase; solo utilícelosstd::tie
para crear tuplas de referencias a campos en el orden de comparación deseado. Generalizando mi ejemplo desde aquí :Cuando "posee" (es decir, puede editar, un factor con las bibliotecas corporativas y de terceros) la clase que desea comparar, y especialmente con la preparación de C ++ 14 para deducir el tipo de retorno de función de la
return
declaración, a menudo es mejor agregar un " empate "función miembro a la clase que desea poder comparar:Entonces las comparaciones anteriores se simplifican a:
Si desea un conjunto más completo de operadores de comparación, sugiero aumentar los operadores (buscar
less_than_comparable
). Si no es adecuado por alguna razón, es posible que le guste o no la idea de macros de soporte (en línea) :... que luego se puede usar a la ...
(Versión de enlace de miembros de C ++ 14 aquí )
Discusión de los detalles de su MyStruct1
Hay implicaciones en la elección de proporcionar un miembro independiente versus un miembro
operator==()
...Implementación independiente
Tienes una decisión interesante que tomar. Como su clase se puede construir implícitamente a partir de a
MyStruct2
, una función independiente / no miembrobool operator==(const MyStruct2& lhs, const MyStruct2& rhs)
admitiría ...... primero creando un temporal
MyStruct1
desdemy_myStruct2
, luego haciendo la comparación. Esto definitivamente dejaríaMyStruct1::an_int
establecido el valor del parámetro predeterminado del constructor de-1
. Dependiendo de si se incluyenan_int
comparación en la implementación de suoperator==
, unaMyStruct1
podría o no podría comparar igual a unaMyStruct2
que sí se compara igual a laMyStruct1
'smy_struct_2
miembro! Además, la creación de un temporalMyStruct1
puede ser una operación muy ineficaz, ya que implica copiar elmy_struct2
miembro existente en un temporal, solo para desecharlo después de la comparación. (Por supuesto, puede evitar esta construcción implícita deMyStruct1
s para la comparación haciendo ese constructorexplicit
o eliminando el valor predeterminado paraan_int
).Implementación de miembros
Si desea evitar la construcción implícita de a
MyStruct1
desde aMyStruct2
, convierta el operador de comparación en una función miembro:Tenga en cuenta que la
const
palabra clave, solo necesaria para la implementación del miembro, le advierte al compilador que comparar objetos no los modifica, por lo que se puede permitir enconst
objetos.Comparando las representaciones visibles
A veces, la forma más fácil de obtener el tipo de comparación que desea puede ser ...
... que a menudo también es muy caro, ¡esos que se
string
crean dolorosamente solo para tirarlos! Para los tipos con valores de punto flotante, comparar representaciones visibles significa que el número de dígitos mostrados determina la tolerancia dentro de la cual los valores casi iguales se tratan como iguales durante la comparación.fuente
int cmp(x, y)
ocompare
función que devuelve un valor negativo parax < y
, 0 por la igualdad y un valor positivo parax > y
se utiliza como base para<
,>
,<=
,>=
,==
, y!=
; es muy fácil usar el CRTP para inyectar todos esos operadores en una clase. Estoy seguro de que publiqué la implementación en una respuesta anterior, pero no pude encontrarla rápidamente.>
,<=
y>=
en cuanto a<
. También podría implementar==
y de!=
esa manera, pero supongo que normalmente no sería una implementación muy eficiente. Sería bueno si no se necesitaran CRTP u otros trucos para todo esto, pero el estándar solo exigiría la generación automática de estos operadores si el usuario no los define explícitamente y<
está definido.==
y!=
puede que no se exprese de manera eficiente usando<
que usar comparar para todo es común. "Sería bueno si no se necesitaría CRTP u otros trucos" - tal vez, pero luego CRTP puede ser fácilmente utilizado para generar gran cantidad de otros operadores (por ejemplo, bit a bit|
,&
,^
de|=
,&=
y^=
,+
-
*
/
%
de sus formas de asignación; binaria-
de la negación unaria y+
) - tantas variaciones potencialmente útiles sobre este tema que solo proporcionar una función de lenguaje para una porción bastante arbitraria de eso no es particularmente elegante.std::tie
para hacer la comparación de varios miembros?Necesita definir explícitamente
operator ==
paraMyStruct1
.Ahora la comparación == es legal para 2 de estos objetos.
fuente
A partir de C ++ 20, debería ser posible añadir un conjunto completo de operadores de comparación predeterminado (
==
,<=
, etc.) a una clase declarando un operador de comparación de tres vías por defecto ( "nave espacial" operador), así:Con un compilador compatible con C ++ 20, agregar esa línea a MyStruct1 y MyStruct2 puede ser suficiente para permitir comparaciones de igualdad, asumiendo que la definición de MyStruct2 es compatible.
fuente
La comparación no funciona en estructuras en C o C ++. En su lugar, compare por campos.
fuente
Por defecto, las estructuras no tienen
==
operador. Tendrás que escribir tu propia implementación:fuente
Fuera de la caja, el operador == solo funciona para primitivas. Para que su código funcione, necesita sobrecargar el operador == para su estructura.
fuente
Porque no escribió un operador de comparación para su estructura. El compilador no lo genera por usted, por lo que si desea una comparación, debe escribirlo usted mismo.
fuente