La pregunta de por qué tiene que proporcionar operator==
no es lo mismo que la pregunta de por qué debe proporcionar alguna función de comparación.
Con respecto a esto último, la razón por la que se le solicita que proporcione la lógica de comparación, es que la igualdad de elemento raras veces es apropiada. Considere, por ejemplo, una estructura POD con una matriz de char
allí. Si se usa ’ s para contener una cadena terminada en cero, entonces dos de estas estructuras pueden comparar desigual en el nivel binario (debido a los contenidos arbitrarios después de los cero bytes en las cadenas) siendo lógicamente equivalente.
Además, aquí están todas las complicaciones de nivel C++ mencionadas por otras respuestas, p. Ej. el especialmente espinoso de la igualdad polimórfica (realmente no se necesita ’ ¡quiero que el compilador elija!).
Por lo tanto, básicamente, simplemente no hay una buena opción predeterminada, por lo que la elección es suya.
En relación con la primera pregunta, que es lo que, literalmente, preguntó, ¿por qué tiene que proporcionar operator==
?
Si define operator<
y operator==
, las definiciones de operador en el espacio de nombres std::rel_ops
pueden completar el resto por usted. Presumiblemente, la razón por la que se necesita operator==
es que sería innecesariamente ineficaz implementarla en términos de operator<
(luego requerir dos comparaciones). Sin embargo, la elección de estos dos operadores como base es completamente desconcertante, porque hace que el código de usuario sea detallado y complicado, y en algunos casos, ¡mucho menos eficiente que el posible!
En mi opinión, la mejor base para los operadores de comparación es la función de tres valores compare
, como std::string::compare
.
Dada una variante de función miembro comparedTo
, a continuación, puede utilizar una clase de patrón de plantilla Curiosamente recurrente como la de abajo, para proporcionar el conjunto completo de operadores:
template< class Derived >
class ComparisionOps
{
public:
friend int compare(Derived const a, Derived const& b)
{
return a.comparedTo(b);
}
friend bool operator<(Derived const a, Derived const b)
{
return (compare(a, b) < 0);
}
friend bool operator<=(Derived const a, Derived const b)
{
return (compare(a, b) <= 0);
}
friend bool operator==(Derived const a, Derived const b)
{
return (compare(a, b) == 0);
}
friend bool operator>=(Derived const a, Derived const b)
{
return (compare(a, b) >= 0);
}
friend bool operator>(Derived const a, Derived const b)
{
return (compare(a, b) > 0);
}
friend bool operator!=(Derived const a, Derived const b)
{
return (compare(a, b) != 0);
}
};
donde compare
es una función sobrecargada, por ejemplo, de esta manera:
template< class Type >
inline bool lt(Type const& a, Type const& b)
{
return std::less<Type>()(a, b);
}
template< class Type >
inline bool eq(Type const& a, Type const& b)
{
return std::equal_to<Type>()(a, b);
}
template< class Type >
inline int compare(Type const& a, Type const b)
{
return (lt(a, b)? -1 : eq(a, b)? 0 : +1);
}
template< class Char >
inline int compare(basic_string<Char> const& a, basic_string<Char> const& b)
{
return a.compare(b);
}
template< class Char >
inline int compareCStrings(Char const a[], Char const b[])
{
typedef char_traits<Char> Traits;
Size const aLen = Traits::length(a);
Size const bLen = Traits::length(b);
// Since there can be negative Char values, cannot rely on comparision stopping
// at zero termination (this can probably be much optimized at assembly level):
int const way = Traits::compare(a, b, min(aLen, bLen));
return (way == 0? compare(aLen, bLen) : way);
}
inline int compare(char const a[], char const b[])
{
return compareCStrings(a, b);
}
inline int compare(wchar_t const a[], wchar_t const b[])
{
return compareCStrings(a, b);
}
Ahora, que ’ s la maquinaria. ¿Qué aspecto tiene aplicarlo a su clase & hellip;
struct Vec3
{
float x, y, z;
};
?
bien que ’ s bastante simple:
struct Vec3
: public ComparisionOps<Vec3>
{
float x, y, z;
int comparedTo(Vec3 const& other) const
{
if(int c = compare(x, other.x)) { return c; }
if(int c = compare(y, other.y)) { return c; }
if(int c = compare(z, other.z)) { return c; }
return 0; // Equal.
}
};
de responsabilidad: Código y hellip no muy probado; :-)
Porque no existe un "comportamiento predeterminado" apropiado cuando se trata de la igualdad. –
@EtiennedeMartel: Podría haber. En Ada, por ejemplo, la igualdad en los registros se define en términos de igualdad de los componentes. –
La igualdad y la desigualdad son igualmente fáciles de definir. –