While I was trying to learn about C++ operators, I stumbled upon the following table that listed a strange comparison operator. What does this <=>
operator do?
Since 2017 cppreference.com updated that page and now contains detailed information about the<=>
operator.
On 2017-11-11, the ISO C++ committee adopted Herb Sutter's proposal for the <=> "spaceship" three-way comparison operator as one of the new features that were added to C++20. In the paper titled Consistent comparison Sutter, Maurer and Brown demonstrate the concepts of the new design. For an overview of the proposal, here's an excerpt from the article:
The expression a <=> b returns an object that compares <0 if a < b, compares >0 if a > b, and compares ==0 if a and b are equal/equivalent.
Common case: To write all comparisons for your type X with type Y, with memberwise semantics, just write:
auto X::operator<=>(const Y&) const = default;
Advanced cases: To write all comparisons for your type X with type Y, just write operator<=> that takes a Y, can use =default to get memberwise semantics if desired, and returns the appropriate category type:
- Return an _ordering if your type naturally supports <, and we’ll efficiently generate symmetric <, >, <=, >=, ==, and !=; otherwise return an _equality, and we’ll efficiently generate symmetric == and !=.
- Return strong_ if for your type a == b implies f(a) == f(b) (substitutability, where f reads only comparison-salient state that is accessible using the public const members), otherwise return weak_.
Comparison Categories |
---|
Five comparison categories are defined as std::
types,
with the following predefined values:
┌──────────────────┬───────────────────────────────────┬─────────────┐
│ │ Numeric values │ Non-numeric │
│ Category ├──────┬────────────┬───────────────┤ │
│ │ -1 │ 0 │ +1 │ values │
├──────────────────┼──────┼────────────┼───────────────┼─────────────┤
│ strong_ordering │ less │ equal │ greater │ │
│ weak_ordering │ less │ equivalent │ greater │ │
│ partial_ordering │ less │ equivalent │ greater │ unordered │
│ strong_equality │ │ equal │ nonequal │ │
│ weak_equality │ │ equivalent │ nonequivalent │ │
└──────────────────┴──────┴────────────┴───────────────┴─────────────┘
Implicit conversions between these types are defined as follows:
strong_ordering
with values {less
, equal
, greater
} implicitly converts to:
weak_ordering
with values {less
, equivalent
, greater
}partial_ordering
with values {less
, equivalent
, greater
}strong_equality
with values {unequal
, equal
, unequal
}weak_equality
with values {nonequivalent
, equivalent
, nonequivalent
}weak_ordering
with values {less
, equivalent
, greater
} implicitly converts to:
partial_ordering
with values {less
, equivalent
, greater
}weak_equality
with values {nonequivalent
, equivalent
, nonequivalent
}partial_ordering
with values {less
, equivalent
, greater
, unordered
} implicitly converts to:
weak_equality
with values {nonequivalent
, equivalent
, nonequivalent
, nonequivalent
}strong_equality
with values {equal
, unequal
} implicitly converts to:
weak_equality
with values {equivalent
, nonequivalent
}Three-way comparison |
---|
The<=>
token is introduced. The character sequence<=>
tokenizes to<= >
, in old source code. For example,X<&Y::operator<=>
needs to add a space to retain its meaning.
The overloadable operator<=>
is a three-way comparison function and has precedence higher than<
and lower than<<
. It returns a type that can be compared against literal0
but other return types are allowed such as to support expression templates. All<=>
operators defined in the language and in the standard library return one of the 5 aforementionedstd::
comparison category types.
For language types, the following built-in<=>
same-type comparisons are provided. All are constexpr, except where noted otherwise. These comparisons cannot be invoked heterogeneously using scalar promotions/conversions.
bool
, integral, and pointer types,<=>
returnsstrong_ordering
.<=>
, and there are built-in heterogeneousoperator<=>(T*, nullptr_t)
. Only comparisons of pointers to the same object/allocation are constant expressions.<=>
returnspartial_ordering
, and can be invoked heterogeneously by widening arguments to a larger floating point type.<=>
returns the same as the enumeration's underlying type's<=>
.nullptr_t
,<=>
returnsstrong_ordering
and always yieldsequal
.T[N] <=> T[N]
returns the same type asT
's<=>
and performs lexicographical elementwise comparison. There is no<=>
for other arrays.void
there is no<=>
.To better understand the inner workings of this operator, please read the original paper. This is just what I've found out using search engines. Also, check out Comparison Operators, including Three-Way Comparison(C++20).