The spaceship operator was proposed by Herb Sutter and was adopted by the committee to be implemented with C++ 20, detailed report can be consulted here, or you if are more into lectures, here you can see a video of the man himself making the case for it. In pages 3/4 of the report you can see the main use case:
The comparison operators implementation, needed for pre C++20, in the following class:
class Point
{
int x;
int y;
public:
friend bool operator==(const Point &a, const Point &b) { return a.x == b.x && a.y == b.y; }
friend bool operator<(const Point &a, const Point &b) { return a.x < b.x || (a.x == b.x && a.y < b.y); }
friend bool operator!=(const Point &a, const Point &b) { return !(a == b); }
friend bool operator<=(const Point &a, const Point &b) { return !(b < a); }
friend bool operator>(const Point &a, const Point &b) { return b < a; }
friend bool operator>=(const Point& a, const Point& b) { return !(a < b); }
// ... non-comparisonfunctions ...
};
Would be replaced by:
class Point
{
int x;
int y;
public:
auto operator<=>(const Point &) const = default;
// ... non-comparison functions ...
};
So to answer your question, overloading operator<=>
as class member allows you to use all comparison operators for the class objects without having to implement them, defaulting it also defaults operator==
, if it's not otherwise declared, which in term automatically implements operator!=
, making all comparison operations available with a single expression. This functionality is the main use case.
I would like to point out that the spaceship operator would not be possible without the introduction of the default comparison feature with C++20.
Defaulted three-way comparison
[...]
Let R
be the return type, each pair of subobjects a
, b
is compared as follows:
[...]
... if R
is std::strong_ordering
, the result is:
a == b ? R::equal : a < b ? R::less : R::greater
Otherwise, if R
is std::weak_ordering
, the result is:
a == b ? R::equivalent : a < b ? R::less : R::greater
Otherwise (R
is std::partial_ordering
), the result is:
a == b ? R::equal : a < b ? R::less : b < a ? R::greater : R::unordered
Per the rules for any operator<=>
overload, a defaulted <=>
overload will also allow the type to be compared with <
, <=
, >
, and >=
.
If operator<=>
is defaulted and operator==
is not declared at all, then operator==
is implicitly defaulted.
It also allows to default operator ==
only, which will implement operator !=
, albeit not as versatile as the former, it's also an interesting possibility.
operator<=>
(or evendefault
ing if possible) saves time (development and maintenance) instead of having to implement all of them manually. If you on the other hand are interested in knowingif( 1.1 < 2.2 )
, then it probably doesn't make much sense to use<=>
– Fasciate<=>
and==
. Less chance of having a mistake/bug than writing 6 comparison operators. – Continuant<=>
to perform a comparison, or about using<=>
in any general context? – Triplenerved