I'm learning about operator overloading in C++, and I see that ==
and !=
are simply some special functions which can be customized for user-defined types. My concern is, though, why are there two separate definitions needed? I thought that if a == b
is true, then a != b
is automatically false, and vice versa, and there is no other possibility, because, by definition, a != b
is !(a == b)
. And I couldn't imagine any situation in which this wasn't true. But perhaps my imagination is limited or I am ignorant of something?
I know that I can define one in terms of the other, but this is not what I'm asking about. I'm also not asking about the distinction between comparing objects by value or by identity. Or whether two objects could be equal and non-equal at the same time (this is definitely not an option! these things are mutually exclusive). What I'm asking about is this:
Is there any situation possible in which asking questions about two objects being equal does make sense, but asking about them not being equal doesn't make sense? (either from the user's perspective, or the implementer's perspective)
If there is no such possibility, then why on Earth does C++ have these two operators being defined as two distinct functions?
You would not want the language to automatically rewrite a != b
as !(a == b)
when a == b
returns something other than a bool
. And there are a few reasons why you might make it do that.
You may have expression builder objects, where a == b
doesn't and isn't intended to perform any comparison, but simply builds some expression node representing a == b
.
You may have lazy evaluation, where a == b
doesn't and isn't intended to perform any comparison directly, but instead returns some kind of lazy<bool>
that can be converted to bool
implicitly or explicitly at some later time to actually perform the comparison. Possibly combined with the expression builder objects to allow complete expression optimisation before evaluation.
You may have some custom optional<T>
template class, where given optional variables t
and u
, you want to allow t == u
, but make it return optional<bool>
.
There's probably more that I didn't think of. And even though in these examples the operation a == b
and a != b
do both make sense, still a != b
isn't the same thing as !(a == b)
, so separate definitions are needed.