c++c++20equality

Why can't an equality check be performed via operator!=?


struct Equal
{
    friend bool operator==(const Equal&, const Equal&);
};

struct Unequal
{
    friend bool operator!=(const Unequal&, const Unequal&);
};

int main()
{
    Equal{} == Equal{};  // OK
    Equal{} != Equal{};  // OK
    Unequal{} == Unequal{}; // Error
    Unequal{} != Unequal{}; // OK
}

The Equal{} != Equal{} expression in the code above is successfully transformed into something like !(Equal{} == Equal{}), so why can't the same thing be done with Unequal{} == Unequal{}?


Solution

  • As mentioned in a comment the way != is synthesized from == is described here. Specifically

    • For x != y, all member, non-member, and built-in operator==s found are added to the set, unless there is a matching operator!=.
    • For equality operator expressions x == y and x != y, a synthesized candidate with the order of the two parameters reversed is added for each member, non-member, and built-in operator==s found, unless there is a matching operator!=.

    That is, only != is synthesized from == but not the other way around. This is how the language is defined.

    Consider that this is a rather recent addition to the language. Prior to C++20, Equal{} != Equal{}; would have failed (and perhaps we didn't even reach the point to wonder why Unequal{} == Unequal{}; fails too, why would it not).

    For, why == is not synthesized from != I can only speculate. In my opinion the current way it is specified is sound: Either you choose to have straightforward comparison operators where !(a == b) == (a!=b). In that case you implement operator== and let operator!= be synthesized. If for whatever reason a != b is not just !(a == b) you can opt-out and implement your custom operator!= in addition to your operator==. There is one way to use the default and one way to opt-out. Having two ways to do the same would add complexity for no gain.