No, in a broad sense. Stepanov would say that if you don’t follow this rule of logic then you get what you deserve. That is why in C++20 they will be by default defined by each other just like he wanted.
In practice, yes, there are at least two scenarios.
- NaN (not-a-number) in IEEE floating point numbers. Two NaN are different and not not equal at the same time.
As noted in the comment. The logical inconsistency is not exactly between ==
and !=
, but it is related: you can do a = b; assert( a != b);
or have assert( a != a )
.
- Expression constructs, aka expression templates, aka DSL.
==
and !=
create two independent expressions. Logically, they should be still be opposites but not in the sense that they are simple Boolean values. Take a look at Boost.Phoenix or Boost.Spirit. These libraries wouldn’t be possible if the language forces to return bools for these operations and one as the negation of the other.
In both cases you can reinterpret the situation to "restore" the logical rule. For example 1) you can say that once there is a NaN in your system the program is not in a logical state anymore. 2) you can say that the "expression" a != b
should be also generated by !(a == b)
even if they are not immediately bools.
So, even if the language lets you, you shouldn’t play with the rules of logic.
There is also the myth that supposedly sometimes checking for inequality should be faster than checking for equality or vise versa, as an excuse to implement them separately which can lead to logical inconsistency.
This is nonsense given the short circuiting of logical operations that are fundamental to C++ and should be of any system built on top of C++.