1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
The C2a standard added the em(three-way comparison) operator tt(<=>),
also known as the hi(spaceship)em(spaceship operator), to the language.
This operator is closely related to comparison classes, covered
in section ref(COMPARISONS). At this point we focus on using the
tt(std::strong_ordering) class: the examples of the spaceship operator
presented in this section all return tt(strong_ordering) objects. These
objects are
itemization(
itt(strong_ordering::equal) if both operands are equal;
itt(strong_ordering::less) if the left-hand side operand is smaller than
the right-hand side operand;
itt(strong_ordering::greater) if the left-hand side operand is greater than
the right-hand side operand.
)
Standard operand conversions are handled by the compiler. Note that
itemization(
it() if one of the operands is of type tt(bool), then the other operand
must also be of type tt(bool);
it() narrowing conversions, except from integral types to floating point
types, are not allowed;
it() when the operands are of identical enumeration types their values are
converted to the underlying numeric integral type, which values are
then compared.
)
Other standard conversions, like lvalue transformations and qualification
conversions (cf. section ref(TEMPFUNARGS)), are automatically performed.
Now about the spaceship operator itself. Why would you want it? Of course, if
it's defined then you can use it. As it's available for integral numeric types
the following correctly compiles:
verb( auto isp = 3 <=> 4;)
whereafter tt(isp's) value can be compared to available
outcome-values:
verb( cout << ( isp == strong_ordering::less ? "less\n" : "not less\n" );)
But that by itself doesn't make the spaceship operator all too
interesting. What em(does) make it interesting is that, in combination with
tt(operator==), it handles em(all) comparison operators. So after providing a
class with tt(operator==) and tt(operator<=>) its objects can be compared for
equality, inequality, and they can be ordered by tt(<, <=, >,) and tt(>=). As
an example consider books. To book owners the titles and author names are the
books' important characterstics. To sort them on book shelfs we must use
tt(operator<), to find a particular book we use tt(operator==), to determine
whether two books are different we use tt(operator!=) and if you want to order
them in an country where Arabic is the main language you might want to sort
them using tt(operator>) considering that the prevalent reading order in those
countries is from right to left. Ignoring constructors, destructors and other
members, then this is the interface of our class tt(Book) (note the inclusion
of the tthi(compare) header file, containing the declarations of the
comparison classes):
verb( #include <string>
#include <compare>
class Book
{
friend bool operator==(Book const &lhs, Book const &rhs);
friend std::strong_ordering operator<=>(Book const &lhs,
Book const &rhs);
std::string d_author;
std::string d_title;
// ...
};)
Both friend-functions are easy to implement:
verb( bool operator==(Book const &lhs, Book const &rhs)
{
return lhs.d_author == rhs.d_author and lhs.d_title == rhs.d_title;
}
strong_ordering operator<=>(Book const &lhs, Book const &rhs)
{
return lhs.d_author < rhs.d_author ? strong_ordering::less :
lhs.d_author > rhs.d_author ? strong_ordering::greater :
lhs.d_title < rhs.d_title ? strong_ordering::less :
lhs.d_title > rhs.d_title ? strong_ordering::greater :
strong_ordering::equal;
})
And that's it! Now all comparison operators (and of course the spaceship
operator itself) are available. The following now compiles flawlessly:
verb(
void books(Book const &b1, Book const &b2)
{
cout << (b1 == b2) << (b1 != b2) << (b1 < b2) <<
(b1 <= b2) << (b1 > b2) << (b1 >= b2) << '\n';
}
)
calling tt(books) for two identical books inserts 100101 into tt(cout).
The spaceship operator is available for integral numeric types and may have
been defined for class types. E.g., it is defined for tt(std::string). It is
not automatically available for floating point types.
|