P0515R3: Consistent comparison
Design
The proposal proposes comparison categories as types in std
: partial_ordering
, weak_ordering
, strong_ordering
, weak_equality
, and strong_equality
. (weak_equality
and strong_equality
are removed in P1959R0.) Making them types enables using the type system to guide the generation of the correct appropriate related comparisons.
partial_ordering
admits all relational operators (==, !=, <, <=, >, >=
), equivalent values can be distinguishable and admits incomparable values. It has 4 valid values:less
,equivalent
,greater
, andunordered
.weak_ordering
admits all relational operators (==, !=, <, <=, >, >=
), equivalent values can be distinguishable and doesn't admit incomparable values. It has 3 valid values:less
,equivalent
, andgreater
. It's convertible topartial_ordering
.strong_ordering
admits all relational operators (==, !=, <, <=, >, >=
), equivalent values are indistinguishable and don't admit incomparable values. It has 3 valid values:less
,equal
, andgreater
. It's convertible toweak_ordering
andpartial_ordering
.
The class template std::common_comparison_category
provides an alias for the strongest comparison category to which all of the template arguments Ts...
can be converted. If there is a T
that is not a comparison category type, the alias is void
.
template <typename... Ts> struct common_comparison_category {};
template <typename... Ts>
using common_comparison_category_t = common_comparison_category<Ts...>::type;
static_assert(std::same_as<
std::common_comparison_category_t<
std::partial_ordering, std::weak_ordering,
std::strong_ordering>,
std::partial_ordering>);
operator<=>
is a generalized comparison function and has precedence higher than <
and lower than <<
. It returns a type that can be compared against the literal 0
. There is no restriction on parameter types. Generic code can deduce a type's ordering from the return type of <=>
. It eliminates redundant comparisons in the implementation, as shown in the following example:
struct pair_t {
std::uint8_t a;
std::uint8_t b;
#if __cplusplus >= 202002L
auto operator<=>(const pair_t &other) const {
if (auto cmp = a <=> other.a; cmp != 0) {
return cmp;
}
return b <=> other.b;
}
#else
bool operator<(const pair_t &other) const {
// The implementation needs to perform 2 comparisons for `a`
if (a < other.a) {
return true;
} else if (a > other.a) {
return false;
}
return b < other.b;
}
#endif
};
- For fundamental
bool
, integral, and pointer types,<=>
returnsstrong_ordering
. - For fundamental floating point types,
<=>
returnspartial_ordering
. - For enumerations,
<=>
returns the same as the enumeration's underlying type's<=>
. - For
nullptr_t
,<=>
returnsstrong_ordering::equal
. - For each STL type that supports comparison,
<=>
returns the appropriate comparison category type and returns consistent results with the existing comparison operators.