Why don't C++ compilers define operator== and operator!=?
The argument that if the compiler can provide a default copy constructor, it should be able to provide a similar default operator==()
makes a certain amount of sense. I think that the reason for the decision not to provide a compiler-generated default for this operator can be guessed by what Stroustrup said about the default copy constructor in "The Design and Evolution of C++" (Section 11.4.1 - Control of Copying):
I personally consider it unfortunate that copy operations are defined by default and I prohibit copying of objects of many of my classes. However, C++ inherited its default assignment and copy constructors from C, and they are frequently used.
So instead of "why doesn't C++ have a default operator==()
?", the question should have been "why does C++ have a default assignment and copy constructor?", with the answer being those items were included reluctantly by Stroustrup for backwards compatibility with C (probably the cause of most of C++'s warts, but also probably the primary reason for C++'s popularity).
For my own purposes, in my IDE the snippet I use for new classes contains declarations for a private assignment operator and copy constructor so that when I gen up a new class I get no default assignment and copy operations - I have to explicitly remove the declaration of those operations from the private:
section if I want the compiler to be able to generate them for me.
Even in C++20, the compiler still won't implicitly generate operator==
for you
struct foo
{
std::string str;
int n;
};
assert(foo{"Anton", 1} == foo{"Anton", 1}); // ill-formed
But you will gain the ability to explicitly default ==
since C++20:
struct foo
{
std::string str;
int n;
// either member form
bool operator==(foo const&) const = default;
// ... or friend form
friend bool operator==(foo const&, foo const&) = default;
};
Defaulting ==
does member-wise ==
(in the same way that the default copy constructor does member-wise copy construction). The new rules also provide the expected relationship between ==
and !=
. For instance, with the declaration above, I can write both:
assert(foo{"Anton", 1} == foo{"Anton", 1}); // ok!
assert(foo{"Anton", 1} != foo{"Anton", 2}); // ok!
This specific feature (defaulting operator==
and symmetry between ==
and !=
) comes from one proposal that was part of the broader language feature that is operator<=>
.
The compiler wouldn't know whether you wanted a pointer comparison or a deep (internal) comparison.
It's safer to just not implement it and let the programmer do that themselves. Then they can make all the assumptions they like.