Outpost Universe Forums

Off Topic => Computers & Programming General => Topic started by: Hooman on December 10, 2018, 03:39:38 PM

Title: Spaceship Operator
Post by: Hooman on December 10, 2018, 03:39:38 PM
Ohh, the Spaceship operator <=> is coming to C++20.

This allows you to define a single three-way comparison operator <=>, and the compiler can auto generate all other comparison operators from it: ==, !=, <, >, <=, >=

Example (from cppreference.com):
Code: cpp [Select]

class Point {
 int x;
 int y;
public:
 auto operator<=>(const Point&) const = default;
 /* ... non-comparison functions ... */
};

/* compiler generates all six relational operators */
Point pt1, pt2;
if (pt1 == pt2) { /*...*/ } /* ok */
std::set<Point> s; /* ok */
s.insert(pt1); /* ok */
if (pt1 <= pt2) { /*...*/ } /* ok, makes only a single call to <=>  */


References:
cppreference.com - Default Comparisons (https://en.cppreference.com/w/cpp/language/default_comparisons)
cppreference.com - Comparison Operators - Three Way Comparison (https://en.cppreference.com/w/cpp/language/operator_comparison#Three-way_comparison)
Library Support for the Spaceship (Comparison) Operator (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0768r1.pdf)


EDIT (leeor_net): Fix code syntax highlighting.
Title: Re: Spaceship Operator
Post by: leeor_net on December 10, 2018, 07:48:37 PM
This is exciting. Having to hand write those freaking operators sucks.
Title: Re: Spaceship Operator
Post by: Vagabond on December 10, 2018, 08:33:03 PM
How does it know when one point is greater than or less than another point without some more code to tell the compiler?

-Brett
Title: Re: Spaceship Operator
Post by: leeor_net on December 10, 2018, 09:39:54 PM
Probably by doing one operator in terms of the other.

E.g., in many implementations of operator> and operator<, the code looks something like this:

Code: [Select]
bool Class::operator>(c)
{
    /* some comparison of members here */
    return true;
}

Class::operator<(c)
{
    return this > c;
}
Title: Re: Spaceship Operator
Post by: Vagabond on December 10, 2018, 10:04:31 PM
But that doesn't tell you which point is actually greater than the other point? The spaceship operator needs some help to understand what greater than or less than means for a point class right?
Title: Re: Spaceship Operator
Post by: Hooman on December 11, 2018, 04:09:42 AM
It's a lot like how strcmp works. You implement the one operator, the spaceship operator, which is effectively 3-valued:

Then, using that single value, from a single operator call, you can determine (compiler generated):

So effectively you get all 6 comparison operators, but only have to implement one.



Previously they had std::rel_ops (https://en.cppreference.com/w/cpp/utility/rel_ops/operator_cmp). Given two operators operator==, and operator<, it would implement the other 4 for you. The problem with std::rel_ops is it didn't play nicely with ADT (https://en.cppreference.com/w/cpp/language/adl) (Argument-Dependent Lookup), so sometimes those operators weren't found. Additionally, it added extra template operators to the global namespace, so all structs would end up getting the extra comparison operators, whether you wanted them or not.

The implementation of std::rel_ops might use the following equivalences:

Note: The above also only require one operator call.

A naive implementation might call two possibly expensive operators:
You want to avoid that.



Another benefit of the <=> operator, is that it can distinguish between the various relational strengths, and only provide overloads that are appropriate. That's a whole other topic, but here are the orderings:




Edit: In regards to a "point" (2D, 3D, etc.), there may be no natural way to do inequality comparisons. Hence the different orderings above, which may exclude auto generation of some comparison operators. In particular, if the return type of the spaceship operator is of the last 2 types, the compiler knows not to generate inequality comparisons.