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?


Solution 1:

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.

Solution 2:

If there is no such possibility, then why on Earth does C++ have these two operators being defined as two distinct functions?

Because you can overload them, and by overloading them you can give them a totally different meaning from their original one.

Take, for example, operator <<, originally the bitwise left shift operator, now commonly overloaded as an insertion operator, like in std::cout << something; totally different meaning from the original one.

So, if you accept that the meaning of an operator changes when you overload it, then there is no reason to prevent user from giving a meaning to operator == that is not exactly the negation of operator !=, though this might be confusing.