I have a struct that's defined like this:
struct Vec3 {
float x, y, z;
}
When I attempted to use std::unique
on a std::vector<Vec3>
, I was met with this error:
Description Resource Path Location Type no match for ‘operator==’ in ‘_first._gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* with _Iterator = Vec3*, _Container = std::vector > == _next._gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* with _Iterator = Vec3*, _Container = std::vector >’ ModelConverter line 4351, external location: /usr/include/c++/4.4.6/bits/stl_algo.h C/C++ Problem
I understand the the necessity of the naievite of the compiler in inequality operators and others (in this case, * would almost certainly not be what I mean), but is this a matter of policy, or is there a technical reason for it that I'm not aware of? There's a default assignment operator, so why no default equality operator?
C++20 adds this capability:
This is currently only implemented in GCC and clang trunk. Note that currently defaulting
operator<=>
is equivalent to also defaultingoperator==
, however there is an accepted proposal to remove this. The proposal suggests having defaultingoperator<=>
also imply (not be equivalent to as it is today) defaultingoperator==
as an extension.Microsoft has documentation on this feature at https://devblogs.microsoft.com/cppblog/simplify-your-code-with-rocket-science-c20s-spaceship-operator/.
There's no technical reason. Pedantically, you might say this is because C doesn't let you compare two structures with
==
, and this is a good reason; that behavior switching when you go to C++ is non-obvious. (Presumably, the reason that C doesn't support that is that field-wise comparison might work for some structs, but definitely not all.)And just from a C++ point of view, what if you have a private field? A default
==
technically exposes that field (indirectly, but still). So would the compiler only generate anoperator==
if there are no private or protected data members?Also, there are classes that have no reasonable definition of equality (empty classes, classes that do not model state but cache it, etc.), or for whom the default equality check might be extremely confusing (classes that wrap pointers).
And then there's inheritance. Deciding what to do for
operator==
in a situation of inheritance is complicated, and it'd be easy for the compiler to make the wrong decision. (For example, if this was what C++ did, we would probably be getting questions about why==
always succeed when you test equality between two objects that are both descendants of an abstract base class and being used with a reference to it.)Basically, it's a thorny problem, and it's safer for the compiler to stay out of it, even considering that you could override whatever the compiler decided.
The question of why you have to provide
operator==
is not the same as the question of why you have to provide some comparison function.Regarding the latter, the reason that you are required to provide the comparison logic, is that element-wise equality is seldom appropriate. Consider, for example, a POD struct with an array of
char
in there. If it’s being used to hold a zero-terminated string, then two such structs can compare unequal at the binary level (due to arbitrary contents after the zero bytes in the strings) yet being logically equivalent.In addition, there are all the C++ level complications mentioned by other answers here, e.g. the especially thorny one of polymorphic equality (you really don’t want the compiler to choose!).
So, essentially, there is simply no good default choice, so the choice is yours.
Regarding the former question, which is what you literally asked, why do you have to provide
operator==
?If you define
operator<
andoperator==
, then the operator definitions in namespacestd::rel_ops
can fill in the rest for you. Presumably the reason whyoperator==
is needed is that it would be needlessly inefficient to implement it in terms ofoperator<
(then requiring two comparisons). However, the choice of these two operators as basis is thoroughly baffling, because it makes user code verbose and complicated, and in some cases much less efficient than possible!The IMHO best basis for comparison operators is instead the three-valued
compare
function, such asstd::string::compare
.Given a member function variant
comparedTo
, you can then use a Curiously Recurring Template Pattern class like the one below, to provide the full set of operators:where
compare
is an overloaded function, e.g. like this:Now, that’s the machinery. What does it look like to apply it to your class …
?
Well it’s pretty simple:
Disclaimer: not very tested code… :-)
What would you like the equality operation to be? All the fields the same? It's not gonna make that decision for you.