The definition of spaceship operator is meant to have a strong definition of ordering, but does this affect the way your client code is written or just how to define your class comparison operators?
Since in other post are missing real world example I'm not fully understanding this part.
Other SO post about spaceship operator:
In PHP 7, a new feature, spaceship operator has been introduced. It is used to compare two expressions. It returns -1, 0 or 1 when first expression is respectively less than, equal to, or greater than second expression.
It's a general comparison operator. It returns either a -1, 0, or +1 depending on whether its receiver is less than, equal to, or greater than its argument.
You can directly use the spaceship operator for int 's (1), for string 's (2), and for vecto r's (3). Thanks to the wandbox online-compiler and the newest GCC, here is the output of the program.
Some very smart people on the standardization committee noticed that the spaceship operator will always perform a lexicographic comparison of elements no matter what. Unconditionally performing lexicographic comparisons can lead to inefficient generated code with the equality operator in particular. The canonical example is comparing two strings.
The spaceship operator determines for two objects A and B whether A < B, A = B, or A > B. The spaceship operator or the compiler can auto-generate it for us. Also, a three-way comparison is a function that will give the entire relationship in one query. Traditionally, strcmp () is such a function. Given two strings it will return an integer where,
Let’s explore the answer to this question. In C++20, the compiler is introduced to a new concept referred to “rewritten” expressions. The spaceship operator, along with operator==, are among the first two candidates subject to rewritten expressions.
You just compare the way you've always done:
a < b
It's just that under the hood, one of the candidate functions for that expression will also find (a <=> b) < 0
and if that candidate exists and happens to be the best viable candidate, then it is invoked.
You typically don't use <=>
directly in "client code", you just use the comparisons that you want directly.
For instance, given:
struct X {
int i;
// this can be = default, just writing it out for clarity
strong_ordering operator<=>(X const& rhs) const { return i <=> rhs.i; }
};
The expression
X{42} < X{57};
will evaluate as X{42} <=> X{57} < 0
(there is no <
candidate, so <=>
non-reversed is trivially the best candidate). X{42} <=> X{57}
evaluates as 42 <=> 57
which is strong_ordering::less
. And that < 0
returns true
. Hence, the initial expression is true
... as expected.
The same operator also directly gives us that X{57} > X{42}
, that X{3} >= X{2}
, etc.
The advantage of <=>
is that you only need to write one operator instead of four, that operator is typically much easier to write than <
, you can properly express the differentiation between partial and total orders, and stacking it is typically more performant (e.g. in the cases like string
).
Additionally, we don't have to live in this weird world where everyone pretends that operator<
is the only relational operator that exists.
<=>
allows the lazy way to also be the performant way. You don't change your client code.
Clients may see performance benefits when there was a using std::rel_ops
(or boost::ordered
etc).
An example
// old and busted
struct Person : boost::totally_ordered<Person>
{
std::string firstname;
std::string lastname
bool operator<(const Person & other)
{
return std::tie(firstname, lastname)
< std::tie(other.firstname, other.lastname);
}
}
// new hotness
struct Person
{
std::string firstname;
std::string lastname;
auto operator<=>(const Person &) = default;
}
int main()
{
Person person1 { "John", "Smith" };
Person person2 { "John", "Smith" };
std::cout << person2 <= person1 << std::endl;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With