Search code examples
c++operator-overloadinglanguage-designequality-operator

Why do I have to overload operator== instead of it being defined implicitly?


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<Vec3, std::allocator > == __next.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* with _Iterator = Vec3*, _Container = std::vector<Vec3, std::allocator >’ 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?


Solution

  • 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 an operator== 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.