Can someone explain the purpose of "Three-way comparison (“spaceship”) and defaulted comparisons"
>>>The value of the expression a <=> b describes which one of a < b, a == b, and a > b is true.
A key part of this feature is that classes that provide this operator can have all of the six traditional, binary relational operators defined implicitly.
The primary purpose of this is reducing boilerplate code. For supporting comparisons one currently has to implement a large set if functions. One for each of <, >, <=, =>, != and ==. However many times the implementation of those 6 functions is similar. Thus lots of code to write.
With operator<=> one can implement a single function and the compiler becomes the smart one. When calling
o1 < o2
or calling
o1 >= o2
the compiler will do a call to the single operator<=> and interpret the return value accordingly.
Notably less repitive typing for the type provider.
What if you want to do an equality operation, but the greater than or less than operators require lots of computation? If an object only defines the space ship operator, then isn't it very likely that you will get a lot of extra computation when all you care baout if the two objects are or aren't equal to each other?
I believe programmers are still free to define specific operators in lieu of the compiler-derived ones for such cases.
I found a blog post which raised similar concerns [0], and P1185 [1] proposes some solutions. I don't know whether they made it into the standard, though.
I read that to mean that it saves you from writing highly redundant operator overloads for comparable classes.
You can think of two types of comparison:
* Those that return a boolean. eg. operator < returns bool, true if less than the operand, false if greater or equal.
* Those that return a 3-way value. An example of this would be strcmp(), which might return -1 if less, 0 if equal, and 1 if greater.
The insight is that if the compiler knows the latter exists, it can fill in the former category, and the programmer doesn't have to write a bunch of extra overloads.
One of the goals is to eliminate boilerplate. If I'm remembering my C++ correctly,!=, <=, >, and >= can be easily defined in terms of < and ==, but programmers were required to spell out the definitions for all the operators manually. With operator<=>, one definition would allow the compiler to generate all 6 operators.
There are some correctness and efficiency concerns operator<=> addresses, too, but I'm not confident I can explain those well.
You can read more in P0515R0 [0], which sort of "rolls up" previous papers discussing comparisons.
Technically you don't even need both '<' and '=='. Just '<=' will do if you follow the mathematical definitions (i.e. a <= b and b <= a implies a == b). This is not always the most efficient, but it's not the worst option.
Ah, you're right. I don't see programmers defining the operators that way very frequently for one reason or another, but perhaps I just need to be exposed to more code bases.
One of the useful things added is that the language can now define a default <=> operator for your own classes, for example if you had struct Foo {int a; int b;} previously you'd have had to define your own comparison operators such as:
bool operator<(const Foo& foo) const
{
if (a < foo.a) return true;
if (a > foo.a) return false;
if (b < foo.b) return true;
if (b > foo.b) return false;
return false;
}
.. and all the other comparison operators that you needed.
But now, you can just say:
auto operator<=>(const Foo&) const = default;
and the compiler will automatically generate all the operators for you.
Probably just a buggy implementation. The C and C++ standards are explicit that `main` return an int and only an int. Never void. This has always been the case. However, the `main` function is the only function where the return statement can be omitted. If it is omitted, it’s an implicit `return 0`.
16 comments
[ 3.8 ms ] story [ 55.7 ms ] thread>>>The value of the expression a <=> b describes which one of a < b, a == b, and a > b is true.
A key part of this feature is that classes that provide this operator can have all of the six traditional, binary relational operators defined implicitly.
With operator<=> one can implement a single function and the compiler becomes the smart one. When calling o1 < o2 or calling o1 >= o2 the compiler will do a call to the single operator<=> and interpret the return value accordingly.
Notably less repitive typing for the type provider.
I found a blog post which raised similar concerns [0], and P1185 [1] proposes some solutions. I don't know whether they made it into the standard, though.
[0]: https://foonathan.net/2018/10/spaceship-proposals/
[1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p118...
You can think of two types of comparison:
* Those that return a boolean. eg. operator < returns bool, true if less than the operand, false if greater or equal.
* Those that return a 3-way value. An example of this would be strcmp(), which might return -1 if less, 0 if equal, and 1 if greater.
The insight is that if the compiler knows the latter exists, it can fill in the former category, and the programmer doesn't have to write a bunch of extra overloads.
There are some correctness and efficiency concerns operator<=> addresses, too, but I'm not confident I can explain those well.
You can read more in P0515R0 [0], which sort of "rolls up" previous papers discussing comparisons.
[0]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p051...
bool operator<(const Foo& foo) const { if (a < foo.a) return true; if (a > foo.a) return false; if (b < foo.b) return true; if (b > foo.b) return false; return false; }
.. and all the other comparison operators that you needed.
But now, you can just say:
auto operator<=>(const Foo&) const = default;
and the compiler will automatically generate all the operators for you.
Assorted snippets demonstrating C++20