c++operator-overloadingc++20

Which operators implictly define / generate other operators in C++?


I know that defining certain operators in C++ lets the compiler generate other operators for a class. From what I read in this cppreference article it seems like the following holds true:

  1. operator== must be explicitly defined (perhaps as default) to be usable.
  2. operator!= is generated from operator== if it is not defined explicitly and operator== is defined.
  3. operator<=> generates the other four relational operators (if all goes to plan, that is operator<=> returns a result possible to interpret by the other four and is well defined for both the original and reverse parameter orders)
  4. operator<=> does NOT generate operator== even if it returns std::strong_ordering which, as I understand, should return an object comparable as equal to 0 if and only if the two compared objects are identical (indistinguishable). I tested this myself with the following code
#include <iostream>

class Foo
{
public:
    int x;
    int y;

    // Lexicographic ordering but by the y member first, and by x second.
    std::strong_ordering operator<=>(const Foo& other)
    {
        if (std::strong_ordering cmp = y <=> other.y; cmp != 0)
            return cmp;
        return x <=> other.x;
    }
};

int main()
{
    Foo f = {1, 1}, g = {1, 0};
    std::cout << (f == g);
}

which returns error no match for ‘operator==’ (operand types are ‘Foo’ and ‘Foo’).

What I want to know is, first of all, WHY DOESN'T operator<=> generate operator== and secondly -- is there a complete list of which operators generate other operators (and which ones), or is that cppreference article complete in that regard and there are no other operators being generated? For instance I'd expect operator+(Foo) and operator-() to generate operator-(Foo), on the basis that subtracting is nothing but adding the additive inverse. This, however, turns out to be untrue, which I also tested.


Solution

  • Which operators implicitly define / generate other operators in C++?

    There is only one situation in which one operator defines/generates another, and that is when you default operator<=> you also get a defaulted operator==. That's the complete list.

    Everything else is not based on declaring operators, it is based on rewriting expressions:

    In your case, f == g simply has no operator== candidate, so it's ill-formed. The original design of <=> also would try to rewrite this expression as (f <=> g) == 0 (again, not generating operator== but rather rewriting the expression). But this was shown to have serious performance issues and so it was changed to not do this. You can read more about Comparisons in C++20 on my blog.

    In this case, since you're doing member-wise comparison, you can simply:

    bool operator==(Foo const&) const = default;
    

    or write it manually if you prefer. Either way, your operator<=> is missing a const - it's important that the comparison operators be symmetric.