c++c++20spaceship-operator

comparison of several variables via logical AND in operator <=>


for example, there is a structure with two fields:

struct point {
    float x, y;
    
    bool operator ==(point p) { return x == p.x && y == p.y; }
    bool operator <(point p) { return x < p.x && y < p.y; }
    bool operator <=(point p) { return x <= p.x && y <= p.y; }
    bool operator >(point p) { return x > p.x && y > p.y; }
    bool operator >=(point p) { return x >= p.x && y >= p.y; }
};

Comparison operators check the condition through logical AND for each variable, how should the <=> operator look like so that its result does not differ from these operators?

I already tried to move all operators to the new <=> back when compilers only began to support it, but neither then nor now have I found a way to implement what I wanted.

The only more or less working version of the code that I found:

std::partial_ordering operator<=> (const point& p) const {
   std::partial_ordering c = x <=> point.x;
   if(y <=> point.y != c) return std::partial_ordering::unordered;
   return c;
}

It produces correct results for < and >, but incorrect results for <= and >=. For example, point(0, 0) <= point(0, 1) is true but here <=> returns unordered.


Solution

  • One of the issues with your relational comparisons is that they're not actually consistent. Namely:

    bool operator ==(point p) { return x == p.x && y == p.y; }
    bool operator <(point p) { return x < p.x && y < p.y; }
    bool operator <=(point p) { return x <= p.x && y <= p.y; }
    

    The definition of p <= q is (p < q) or (p == q). But that's not what's actually going on here.

    Considering your example where p is (0, 0) and q is (0, 1):

    Yet, nevertheless:

    That's inconsistent.

    Your operator<=> is actually correct, it just helped expose the fact that your operator<= and operator>= are incorrect.