Search code examples
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):

    • p == q is false (they're not the same)
    • p < q is false (because while p.y < q.y, it is not the case that p.x < q.x)

    Yet, nevertheless:

    • p <= q is true (because p.x <= q.x and also p.y <= q.y)

    That's inconsistent.

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