17 Language support library [support] (original) (raw)

17.11 Comparisons [cmp]

17.11.1 Header synopsis [compare.syn]

The header <compare> specifies types, objects, and functions for use primarily in connection with the three-way comparison operator.

namespace std {

class partial_ordering; class weak_ordering; class strong_ordering;

constexpr bool is_eq (partial_ordering cmp) noexcept { return cmp == 0; } constexpr bool is_neq (partial_ordering cmp) noexcept { return cmp != 0; } constexpr bool is_lt (partial_ordering cmp) noexcept { return cmp < 0; } constexpr bool is_lteq(partial_ordering cmp) noexcept { return cmp <= 0; } constexpr bool is_gt (partial_ordering cmp) noexcept { return cmp > 0; } constexpr bool is_gteq(partial_ordering cmp) noexcept { return cmp >= 0; }

template<class... Ts> struct common_comparison_category { using type = see below; }; template<class... Ts> using common_comparison_category_t = typename common_comparison_category<Ts...>::type;

template<class T, class Cat = partial_ordering> concept three_way_comparable = see below; template<class T, class U, class Cat = partial_ordering> concept three_way_comparable_with = see below;

template<class T, class U = T> struct compare_three_way_result;

template<class T, class U = T> using compare_three_way_result_t = typename compare_three_way_result<T, U>::type;

struct compare_three_way;

inline namespace unspecified { inline constexpr unspecified strong_order = unspecified; inline constexpr unspecified weak_order = unspecified; inline constexpr unspecified partial_order = unspecified; inline constexpr unspecified compare_strong_order_fallback = unspecified; inline constexpr unspecified compare_weak_order_fallback = unspecified; inline constexpr unspecified compare_partial_order_fallback = unspecified; } }

17.11.2 Comparison category types [cmp.categories]

17.11.2.1 Preamble [cmp.categories.pre]

The typespartial_­ordering,weak_­ordering, andstrong_­orderingare collectively termed the comparison category types.

Each is specified in terms of an exposition-only data member named valuewhose value typically corresponds to that of an enumerator from one of the following exposition-only enumerations:

enum class eq { equal = 0, equivalent = equal, nonequal = 1, nonequivalent = nonequal };
enum class ord { less = -1, greater = 1 };
enum class ncmp { unordered = -127 };

[ Note

:

The type strong_­orderingcorresponds to the term total ordering in mathematics.

end note

]

The relational and equality operators for the comparison category types are specified with an anonymous parameter of unspecified type.

This type shall be selected by the implementation such that these parameters can accept literal 0 as a corresponding argument.

[ Example

:

nullptr_­tmeets this requirement.

end example

]

In this context, the behavior of a program that supplies an argument other than a literal 0 is undefined.

For the purposes of subclause [cmp.categories],substitutability is the property that f(a) == f(b) is truewhenever a == b is true, where f denotes a function that reads only comparison-salient state that is accessible via the argument's public const members.

17.11.2.2 Class partial_­ordering [cmp.partialord]

The partial_­ordering type is typically used as the result type of a three-way comparison operatorthat (a) admits all of the six two-way comparison operators ([expr.rel], [expr.eq]), (b) does not imply substitutability, and (c) permits two values to be incomparable.215

namespace std { class partial_ordering { int value;
bool is_ordered;

constexpr explicit
  partial_ordering(eq v) noexcept : value(int(v)), is_ordered(true) {}      
constexpr explicit
  partial_ordering(ord v) noexcept : value(int(v)), is_ordered(true) {}     
constexpr explicit
  partial_ordering(ncmp v) noexcept : value(int(v)), is_ordered(false) {}   

public:

static const partial_ordering less;
static const partial_ordering equivalent;
static const partial_ordering greater;
static const partial_ordering unordered;


friend constexpr bool operator==(partial_ordering v, unspecified) noexcept;
friend constexpr bool operator==(partial_ordering v, partial_ordering w) noexcept = default;
friend constexpr bool operator< (partial_ordering v, unspecified) noexcept;
friend constexpr bool operator> (partial_ordering v, unspecified) noexcept;
friend constexpr bool operator<=(partial_ordering v, unspecified) noexcept;
friend constexpr bool operator>=(partial_ordering v, unspecified) noexcept;
friend constexpr bool operator< (unspecified, partial_ordering v) noexcept;
friend constexpr bool operator> (unspecified, partial_ordering v) noexcept;
friend constexpr bool operator<=(unspecified, partial_ordering v) noexcept;
friend constexpr bool operator>=(unspecified, partial_ordering v) noexcept;
friend constexpr partial_ordering operator<=>(partial_ordering v, unspecified) noexcept;
friend constexpr partial_ordering operator<=>(unspecified, partial_ordering v) noexcept;

};

inline constexpr partial_ordering partial_ordering::less(ord::less); inline constexpr partial_ordering partial_ordering::equivalent(eq::equivalent); inline constexpr partial_ordering partial_ordering::greater(ord::greater); inline constexpr partial_ordering partial_ordering::unordered(ncmp::unordered); }

constexpr bool operator==(partial_ordering v, unspecified) noexcept;constexpr bool operator< (partial_ordering v, unspecified) noexcept;constexpr bool operator> (partial_ordering v, unspecified) noexcept;constexpr bool operator<=(partial_ordering v, unspecified) noexcept;constexpr bool operator>=(partial_ordering v, unspecified) noexcept;

Returns:For operator@, v.is_­ordered && v.value @ 0.

constexpr bool operator< (unspecified, partial_ordering v) noexcept;constexpr bool operator> (unspecified, partial_ordering v) noexcept;constexpr bool operator<=(unspecified, partial_ordering v) noexcept;constexpr bool operator>=(unspecified, partial_ordering v) noexcept;

Returns:For operator@, v.is_­ordered && 0 @ v.value.

constexpr partial_ordering operator<=>(partial_ordering v, unspecified) noexcept;

constexpr partial_ordering operator<=>(unspecified, partial_ordering v) noexcept;

Returns: v < 0 ? partial_­ordering​::​greater : v > 0 ? partial_­ordering​::​less : v.

17.11.2.3 Class weak_­ordering [cmp.weakord]

The weak_­ordering type is typically used as the result type of a three-way comparison operatorthat (a) admits all of the six two-way comparison operators ([expr.rel], [expr.eq]), and (b) does not imply substitutability.

namespace std { class weak_ordering { int value;

constexpr explicit weak_ordering(eq v) noexcept : value(int(v)) {}  
constexpr explicit weak_ordering(ord v) noexcept : value(int(v)) {} 

public:

static const weak_ordering less;
static const weak_ordering equivalent;
static const weak_ordering greater;


constexpr operator partial_ordering() const noexcept;


friend constexpr bool operator==(weak_ordering v, unspecified) noexcept;
friend constexpr bool operator==(weak_ordering v, weak_ordering w) noexcept = default;
friend constexpr bool operator< (weak_ordering v, unspecified) noexcept;
friend constexpr bool operator> (weak_ordering v, unspecified) noexcept;
friend constexpr bool operator<=(weak_ordering v, unspecified) noexcept;
friend constexpr bool operator>=(weak_ordering v, unspecified) noexcept;
friend constexpr bool operator< (unspecified, weak_ordering v) noexcept;
friend constexpr bool operator> (unspecified, weak_ordering v) noexcept;
friend constexpr bool operator<=(unspecified, weak_ordering v) noexcept;
friend constexpr bool operator>=(unspecified, weak_ordering v) noexcept;
friend constexpr weak_ordering operator<=>(weak_ordering v, unspecified) noexcept;
friend constexpr weak_ordering operator<=>(unspecified, weak_ordering v) noexcept;

};

inline constexpr weak_ordering weak_ordering::less(ord::less); inline constexpr weak_ordering weak_ordering::equivalent(eq::equivalent); inline constexpr weak_ordering weak_ordering::greater(ord::greater); }

constexpr operator partial_ordering() const noexcept;

Returns:

value == 0 ? partial_ordering::equivalent : value < 0 ? partial_ordering::less : partial_ordering::greater

constexpr bool operator==(weak_ordering v, unspecified) noexcept;constexpr bool operator< (weak_ordering v, unspecified) noexcept;constexpr bool operator> (weak_ordering v, unspecified) noexcept;constexpr bool operator<=(weak_ordering v, unspecified) noexcept;constexpr bool operator>=(weak_ordering v, unspecified) noexcept;

Returns: v.value @ 0 for operator@.

constexpr bool operator< (unspecified, weak_ordering v) noexcept;constexpr bool operator> (unspecified, weak_ordering v) noexcept;constexpr bool operator<=(unspecified, weak_ordering v) noexcept;constexpr bool operator>=(unspecified, weak_ordering v) noexcept;

Returns: 0 @ v.value for operator@.

constexpr weak_ordering operator<=>(weak_ordering v, unspecified) noexcept;

constexpr weak_ordering operator<=>(unspecified, weak_ordering v) noexcept;

Returns: v < 0 ? weak_­ordering​::​greater : v > 0 ? weak_­ordering​::​less : v.

17.11.2.4 Class strong_­ordering [cmp.strongord]

The strong_­ordering type is typically used as the result type of a three-way comparison operatorthat (a) admits all of the six two-way comparison operators ([expr.rel], [expr.eq]), and (b) does imply substitutability.

namespace std { class strong_ordering { int value;

constexpr explicit strong_ordering(eq v) noexcept : value(int(v)) {}    
constexpr explicit strong_ordering(ord v) noexcept : value(int(v)) {}   

public:

static const strong_ordering less;
static const strong_ordering equal;
static const strong_ordering equivalent;
static const strong_ordering greater;


constexpr operator partial_ordering() const noexcept;
constexpr operator weak_ordering() const noexcept;


friend constexpr bool operator==(strong_ordering v, unspecified) noexcept;
friend constexpr bool operator==(strong_ordering v, strong_ordering w) noexcept = default;
friend constexpr bool operator< (strong_ordering v, unspecified) noexcept;
friend constexpr bool operator> (strong_ordering v, unspecified) noexcept;
friend constexpr bool operator<=(strong_ordering v, unspecified) noexcept;
friend constexpr bool operator>=(strong_ordering v, unspecified) noexcept;
friend constexpr bool operator< (unspecified, strong_ordering v) noexcept;
friend constexpr bool operator> (unspecified, strong_ordering v) noexcept;
friend constexpr bool operator<=(unspecified, strong_ordering v) noexcept;
friend constexpr bool operator>=(unspecified, strong_ordering v) noexcept;
friend constexpr strong_ordering operator<=>(strong_ordering v, unspecified) noexcept;
friend constexpr strong_ordering operator<=>(unspecified, strong_ordering v) noexcept;

};

inline constexpr strong_ordering strong_ordering::less(ord::less); inline constexpr strong_ordering strong_ordering::equal(eq::equal); inline constexpr strong_ordering strong_ordering::equivalent(eq::equivalent); inline constexpr strong_ordering strong_ordering::greater(ord::greater); }

constexpr operator partial_ordering() const noexcept;

Returns:

value == 0 ? partial_ordering::equivalent : value < 0 ? partial_ordering::less : partial_ordering::greater

constexpr operator weak_ordering() const noexcept;

Returns:

value == 0 ? weak_ordering::equivalent : value < 0 ? weak_ordering::less : weak_ordering::greater

constexpr bool operator==(strong_ordering v, unspecified) noexcept;constexpr bool operator< (strong_ordering v, unspecified) noexcept;constexpr bool operator> (strong_ordering v, unspecified) noexcept;constexpr bool operator<=(strong_ordering v, unspecified) noexcept;constexpr bool operator>=(strong_ordering v, unspecified) noexcept;

Returns: v.value @ 0 for operator@.

constexpr bool operator< (unspecified, strong_ordering v) noexcept;constexpr bool operator> (unspecified, strong_ordering v) noexcept;constexpr bool operator<=(unspecified, strong_ordering v) noexcept;constexpr bool operator>=(unspecified, strong_ordering v) noexcept;

Returns: 0 @ v.value for operator@.

constexpr strong_ordering operator<=>(strong_ordering v, unspecified) noexcept;

constexpr strong_ordering operator<=>(unspecified, strong_ordering v) noexcept;

Returns: v < 0 ? strong_­ordering​::​greater : v > 0 ? strong_­ordering​::​less : v.

17.11.3 Class template common_­comparison_­category [cmp.common]

The type common_­comparison_­category provides an alias for the strongest comparison category to which all of the template arguments can be converted.

[ Note

:

A comparison category type is stronger than another if they are distinct types and an instance of the former can be converted to an instance of the latter.

end note

]

template<class... Ts> struct common_comparison_category { using type = see below;};

Remarks:The member typedef-name type denotes the common comparison type ([class.spaceship]) of Ts..., the expanded parameter pack, orvoid if any element of Tsis not a comparison category type.

[ Note

:

This is std​::​strong_­ordering if the expansion is empty.

end note

]

17.11.4 Concept three_­way_­comparable [cmp.concept]

template<class T, class Cat> concept compares-as =
same_as<common_comparison_category_t<T, Cat>, Cat>;

template<class T, class U> concept partially-ordered-with =
requires(const remove_reference_t& t, const remove_reference_t& u) { { t < u } -> boolean-testable; { t > u } -> boolean-testable; { t <= u } -> boolean-testable; { t >= u } -> boolean-testable; { u < t } -> boolean-testable; { u > t } -> boolean-testable; { u <= t } -> boolean-testable; { u >= t } -> boolean-testable; };

Let t and u be lvalues of types const remove_­reference_­t<T> andconst remove_­reference_­t<U>, respectively.

T and U modelpartially-ordered-with<T, U> only if:

template<class T, class Cat = partial_ordering> concept three_way_comparable = weakly-equality-comparable-with<T, T> && partially-ordered-with<T, T> && requires(const remove_reference_t& a, const remove_reference_t& b) { { a <=> b } -> compares-as; };

Let a and b be lvalues of type const remove_­reference_­t<T>.

T and Catmodel three_­way_­comparable<T, Cat> only if:

template<class T, class U, class Cat = partial_ordering> concept three_way_comparable_with = three_way_comparable<T, Cat> && three_way_comparable<U, Cat> && common_reference_with<const remove_reference_t&, const remove_reference_t&> && three_way_comparable< common_reference_t<const remove_reference_t&, const remove_reference_t&>, Cat> && weakly-equality-comparable-with<T, U> && partially-ordered-with<T, U> && requires(const remove_reference_t& t, const remove_reference_t& u) { { t <=> u } -> compares-as; { u <=> t } -> compares-as; };

Let t and u be lvalues of types const remove_­reference_­t<T> andconst remove_­reference_­t<U>, respectively.

Let C becommon_­reference_­t<const remove_­reference_­t<T>&, const remove_­reference_­t<U>&>.

T, U, and Catmodel three_­way_­comparable_­with<T, U, Cat> only if:

17.11.5 Result of three-way comparison [cmp.result]

The behavior of a program that adds specializations for the compare_­three_­way_­result template defined in this subclause is undefined.

For the compare_­three_­way_­result type trait applied to the types T and U, let t and u denote lvalues of typesconst remove_­reference_­t<T> and const remove_­reference_­t<U>, respectively.

If the expression t <=> u is well-formed when treated as an unevaluated operand ([expr.context]), the member typedef-name typedenotes the type decltype(t <=> u).

Otherwise, there is no member type.

17.11.6 Comparison algorithms [cmp.alg]

Given subexpressions E and F, the expression strong_­order(E, F)is expression-equivalent ([defns.expression-equivalent]) to the following:

Given subexpressions E and F, the expression weak_­order(E, F)is expression-equivalent ([defns.expression-equivalent]) to the following:

Given subexpressions E and F, the expression partial_­order(E, F)is expression-equivalent ([defns.expression-equivalent]) to the following:

Given subexpressions E and F, the expression compare_­strong_­order_­fallback(E, F)is expression-equivalent ([defns.expression-equivalent]) to:

except that E and F are evaluated only once.

Given subexpressions E and F, the expression compare_­weak_­order_­fallback(E, F)is expression-equivalent ([defns.expression-equivalent]) to:

except that E and F are evaluated only once.

Given subexpressions E and F, the expression compare_­partial_­order_­fallback(E, F)is expression-equivalent ([defns.expression-equivalent]) to:

except that E and F are evaluated only once.