Files
2025-10-25 03:02:53 +03:00

840 lines
41 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[cmp]
# 17 Language support library [[support]](./#support)
## 17.12 Comparisons [cmp]
### [17.12.1](#compare.syn) Header <compare> synopsis [[compare.syn]](compare.syn)
[1](#compare.syn-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L4783)
The header <compare> specifies types, objects, and functions
for use primarily in connection with
the [three-way comparison operator](expr.spaceship "7.6.8Three-way comparison operator[expr.spaceship]")[.](#compare.syn-1.sentence-1)
[🔗](#lib:is_eq)
// all freestandingnamespace std {// [[cmp.categories]](#categories "17.12.2Comparison category types"), comparison category typesclass partial_ordering; class weak_ordering; class strong_ordering; // named comparison functionsconstexpr 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; }// [[cmp.common]](#common "17.12.3Class template common_­comparison_­category"), common comparison category typetemplate<class... Ts>struct common_comparison_category {using type = *see below*; }; template<class... Ts>using common_comparison_category_t = typename common_comparison_category<Ts...>::type; // [[cmp.concept]](#concept "17.12.4Concept three_­way_­comparable"), concept [three_way_comparable](#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")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*; // [[cmp.result]](#result "17.12.5Result of three-way comparison"), result of three-way comparisontemplate<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; // [[comparisons.three.way]](comparisons.three.way "22.10.8.8Class compare_­three_­way"), class compare_three_waystruct compare_three_way; // [[cmp.alg]](#alg "17.12.6Comparison algorithms"), comparison algorithmsinline 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*; }// [[compare.type]](#compare.type "17.12.7Type Ordering"), type orderingtemplate<class T, class U>struct type_order; template<class T, class U>constexpr strong_ordering type_order_v = type_order<T, U>::value;}
### [17.12.2](#categories) Comparison category types [[cmp.categories]](cmp.categories)
#### [17.12.2.1](#categories.pre) Preamble [[cmp.categories.pre]](cmp.categories.pre)
[1](#categories.pre-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L4859)
The typespartial_ordering,weak_ordering, andstrong_ordering are collectively termed the [*comparison category types*](#def:comparison_category_types "17.12.2.1Preamble[cmp.categories.pre]")[.](#categories.pre-1.sentence-1)
Each is specified in terms of an exposition-only data member named value whose value typically corresponds to that of an enumerator
from one of the following exposition-only enumerations:enum class *ord* { *equal* = 0, *equivalent* = *equal*, *less* = -1, *greater* = 1 }; // *exposition only*enum class *ncmp* { *unordered* = -127 }; // *exposition only*
[2](#categories.pre-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L4873)
[*Note [1](#categories.pre-note-1)*:
The type strong_ordering corresponds to the term
total ordering in mathematics[.](#categories.pre-2.sentence-1)
— *end note*]
[3](#categories.pre-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L4880)
The relational and equality operators for the comparison category types
are specified with an anonymous parameter of unspecified type[.](#categories.pre-3.sentence-1)
This type shall be selected by the implementation such that
these parameters can accept literal 0 as a corresponding argument[.](#categories.pre-3.sentence-2)
[*Example [1](#categories.pre-example-1)*:
nullptr_t meets this requirement[.](#categories.pre-3.sentence-3)
— *end example*]
In this context, the behavior of a program that supplies
an argument other than a literal 0 is undefined[.](#categories.pre-3.sentence-4)
[4](#categories.pre-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L4892)
For the purposes of [[cmp.categories]](#categories "17.12.2Comparison category types"),[*substitutability*](#def:substitutability "17.12.2.1Preamble[cmp.categories.pre]") is the property that f(a) == f(b) is true whenever 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[.](#categories.pre-4.sentence-1)
#### [17.12.2.2](#partialord) Class partial_ordering [[cmp.partialord]](cmp.partialord)
[1](#partialord-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L4901)
The partial_ordering type is typically used
as the result type of a three-way comparison operator ([[expr.spaceship]](expr.spaceship "7.6.8Three-way comparison operator"))
for a type that admits
all of the six two-way comparison operators ([[expr.rel]](expr.rel "7.6.9Relational operators"), [[expr.eq]](expr.eq "7.6.10Equality operators")),
for which equality need not imply substitutability,
and that permits two values to be incomparable[.](#partialord-1.sentence-1)[190](#footnote-190 "That is, a &lt; b, a == b, and a > b might all be false.")
[🔗](#lib:partial_ordering)
namespace std {class partial_ordering {int *value*; // *exposition only*bool *is-ordered*; // *exposition only*// exposition-only constructorsconstexpr explicit partial_ordering(*ord* v) noexcept : *value*(int(v)), *is-ordered*(true) {} // *exposition only*constexpr explicit partial_ordering(*ncmp* v) noexcept : *value*(int(v)), *is-ordered*(false) {} // *exposition only*public:// valid valuesstatic const partial_ordering less; static const partial_ordering equivalent; static const partial_ordering greater; static const partial_ordering unordered; // comparisonsfriend 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; }; // valid values' definitionsinline constexpr partial_ordering partial_ordering::less(*ord*::*less*); inline constexpr partial_ordering partial_ordering::equivalent(*ord*::*equivalent*); inline constexpr partial_ordering partial_ordering::greater(*ord*::*greater*); inline constexpr partial_ordering partial_ordering::unordered(*ncmp*::*unordered*);}
[🔗](#lib:operator==,partial_ordering)
`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;
`
[2](#partialord-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L4973)
*Returns*: For operator@, v.*is-ordered* && v.*value* @ 0[.](#partialord-2.sentence-1)
[🔗](#lib:operator%3c,partial_ordering_)
`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;
`
[3](#partialord-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L4990)
*Returns*: For operator@, v.*is-ordered* && 0 @ v.*value*[.](#partialord-3.sentence-1)
[🔗](#lib:operator%3c=%3e,partial_ordering)
`constexpr partial_ordering operator<=>(partial_ordering v, unspecified) noexcept;
`
[4](#partialord-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5001)
*Returns*: v[.](#partialord-4.sentence-1)
[🔗](#lib:operator%3c=%3e,partial_ordering_)
`constexpr partial_ordering operator<=>(unspecified, partial_ordering v) noexcept;
`
[5](#partialord-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5012)
*Returns*: v < 0 ? partial_ordering::greater : v > 0 ? partial_ordering::less : v[.](#partialord-5.sentence-1)
[190)](#footnote-190)[190)](#footnoteref-190)
That is, a < b, a == b, and a > b might all be false[.](#footnote-190.sentence-1)
#### [17.12.2.3](#weakord) Class weak_ordering [[cmp.weakord]](cmp.weakord)
[1](#weakord-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5019)
The weak_ordering type is typically used
as the result type of a three-way comparison operator ([[expr.spaceship]](expr.spaceship "7.6.8Three-way comparison operator"))
for a type that admits
all of the six two-way comparison operators ([[expr.rel]](expr.rel "7.6.9Relational operators"), [[expr.eq]](expr.eq "7.6.10Equality operators"))
and for which equality need not imply substitutability[.](#weakord-1.sentence-1)
[🔗](#lib:weak_ordering)
namespace std {class weak_ordering {int *value*; // *exposition only*// exposition-only constructorsconstexpr explicit weak_ordering(*ord* v) noexcept : *value*(int(v)) {} // *exposition only*public:// valid valuesstatic const weak_ordering less; static const weak_ordering equivalent; static const weak_ordering greater; // conversionsconstexpr operator partial_ordering() const noexcept; // comparisonsfriend 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; }; // valid values' definitionsinline constexpr weak_ordering weak_ordering::less(*ord*::*less*); inline constexpr weak_ordering weak_ordering::equivalent(*ord*::*equivalent*); inline constexpr weak_ordering weak_ordering::greater(*ord*::*greater*);}
[🔗](#lib:operator_partial_ordering,weak_ordering)
`constexpr operator partial_ordering() const noexcept;
`
[2](#weakord-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5075)
*Returns*: *value* == 0 ? partial_ordering::equivalent :*value* < 0 ? partial_ordering::less : partial_ordering::greater
[🔗](#lib:operator==,weak_ordering)
`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;
`
[3](#weakord-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5098)
*Returns*: v.*value* @ 0 for operator@[.](#weakord-3.sentence-1)
[🔗](#lib:operator%3c,weak_ordering_)
`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;
`
[4](#weakord-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5115)
*Returns*: 0 @ v.*value* for operator@[.](#weakord-4.sentence-1)
[🔗](#lib:operator%3c=%3e,weak_ordering)
`constexpr weak_ordering operator<=>(weak_ordering v, unspecified) noexcept;
`
[5](#weakord-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5126)
*Returns*: v[.](#weakord-5.sentence-1)
[🔗](#lib:operator%3c=%3e,weak_ordering_)
`constexpr weak_ordering operator<=>(unspecified, weak_ordering v) noexcept;
`
[6](#weakord-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5137)
*Returns*: v < 0 ? weak_ordering::greater : v > 0 ? weak_ordering::less : v[.](#weakord-6.sentence-1)
#### [17.12.2.4](#strongord) Class strong_ordering [[cmp.strongord]](cmp.strongord)
[1](#strongord-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5144)
The strong_ordering type is typically used
as the result type of a three-way comparison operator ([[expr.spaceship]](expr.spaceship "7.6.8Three-way comparison operator"))
for a type that admits
all of the six two-way comparison operators ([[expr.rel]](expr.rel "7.6.9Relational operators"), [[expr.eq]](expr.eq "7.6.10Equality operators"))
and for which equality does imply substitutability[.](#strongord-1.sentence-1)
[🔗](#lib:strong_ordering)
namespace std {class strong_ordering {int *value*; // *exposition only*// exposition-only constructorsconstexpr explicit strong_ordering(*ord* v) noexcept : *value*(int(v)) {} // *exposition only*public:// valid valuesstatic const strong_ordering less; static const strong_ordering equal; static const strong_ordering equivalent; static const strong_ordering greater; // conversionsconstexpr operator partial_ordering() const noexcept; constexpr operator weak_ordering() const noexcept; // comparisonsfriend 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; }; // valid values' definitionsinline constexpr strong_ordering strong_ordering::less(*ord*::*less*); inline constexpr strong_ordering strong_ordering::equal(*ord*::*equal*); inline constexpr strong_ordering strong_ordering::equivalent(*ord*::*equivalent*); inline constexpr strong_ordering strong_ordering::greater(*ord*::*greater*);}
[🔗](#lib:operator_partial_ordering,strong_ordering)
`constexpr operator partial_ordering() const noexcept;
`
[2](#strongord-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5204)
*Returns*: *value* == 0 ? partial_ordering::equivalent :*value* < 0 ? partial_ordering::less : partial_ordering::greater
[🔗](#lib:operator_weak_ordering,strong_ordering)
`constexpr operator weak_ordering() const noexcept;
`
[3](#strongord-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5219)
*Returns*: *value* == 0 ? weak_ordering::equivalent :*value* < 0 ? weak_ordering::less : weak_ordering::greater
[🔗](#lib:operator==,strong_ordering)
`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;
`
[4](#strongord-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5242)
*Returns*: v.*value* @ 0 for operator@[.](#strongord-4.sentence-1)
[🔗](#lib:operator%3c,strong_ordering_)
`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;
`
[5](#strongord-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5259)
*Returns*: 0 @ v.*value* for operator@[.](#strongord-5.sentence-1)
[🔗](#lib:operator%3c=%3e,strong_ordering)
`constexpr strong_ordering operator<=>(strong_ordering v, unspecified) noexcept;
`
[6](#strongord-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5270)
*Returns*: v[.](#strongord-6.sentence-1)
[🔗](#lib:operator%3c=%3e,strong_ordering_)
`constexpr strong_ordering operator<=>(unspecified, strong_ordering v) noexcept;
`
[7](#strongord-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5281)
*Returns*: v < 0 ? strong_ordering::greater : v > 0 ? strong_ordering::less : v[.](#strongord-7.sentence-1)
### [17.12.3](#common) Class template common_comparison_category [[cmp.common]](cmp.common)
[1](#common-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5288)
The type common_comparison_category provides an alias for
the strongest comparison category
to which all of the template arguments can be converted[.](#common-1.sentence-1)
[*Note [1](#common-note-1)*:
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[.](#common-1.sentence-2)
— *end note*]
[🔗](#lib:common_comparison_category)
`template<class... Ts>
struct common_comparison_category {
using type = see below;
};
`
[2](#common-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5307)
*Remarks*: The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") type denotes
the common comparison type ([[class.spaceship]](class.spaceship "11.10.3Three-way comparison")) of Ts...,
the expanded parameter pack, orvoid if any element of Ts is not a comparison category type[.](#common-2.sentence-1)
[*Note [2](#common-note-2)*:
This is std::strong_ordering if the expansion is empty[.](#common-2.sentence-2)
— *end note*]
### [17.12.4](#concept) Concept three_way_comparable [[cmp.concept]](cmp.concept)
template<class T, class Cat>concept [*compares-as*](#concept:compares-as "17.12.4Concept three_­way_­comparable[cmp.concept]") = // *exposition only*[same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<common_comparison_category_t<T, Cat>, Cat>;
template<class T, class U>concept [*partially-ordered-with*](#concept:partially-ordered-with "17.12.4Concept three_­way_­comparable[cmp.concept]") = // *exposition only*requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {{ t < u } -> [*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]"); { t > u } -> [*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]"); { t <= u } -> [*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]"); { t >= u } -> [*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]"); { u < t } -> [*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]"); { u > t } -> [*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]"); { u <= t } -> [*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]"); { u >= t } -> [*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]"); };
[1](#concept-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5340)
Let t and u be
lvalues of types const remove_reference_t<T> andconst remove_reference_t<U>, respectively[.](#concept-1.sentence-1)
T and U model[*partially-ordered-with*](#concept:partially-ordered-with "17.12.4Concept three_­way_­comparable[cmp.concept]")<T, U> only if
- [(1.1)](#concept-1.1)
t < u, t <= u, t > u, t >= u, u < t, u <= t, u > t, and u >= t have the same domain,
- [(1.2)](#concept-1.2)
bool(t < u) == bool(u > t) is true,
- [(1.3)](#concept-1.3)
bool(u < t) == bool(t > u) is true,
- [(1.4)](#concept-1.4)
bool(t <= u) == bool(u >= t) is true, and
- [(1.5)](#concept-1.5)
bool(u <= t) == bool(t >= u) is true[.](#concept-1.sentence-2)
template<class T, class Cat = partial_ordering>concept [three_way_comparable](#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]") =[*weakly-equality-comparable-with*](concept.equalitycomparable#concept:weakly-equality-comparable-with "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<T, T> &&[*partially-ordered-with*](#concept:partially-ordered-with "17.12.4Concept three_­way_­comparable[cmp.concept]")<T, T> &&requires(const remove_reference_t<T>& a, const remove_reference_t<T>& b) {{ a <=> b } -> [*compares-as*](#concept:compares-as "17.12.4Concept three_­way_­comparable[cmp.concept]")<Cat>; };
[2](#concept-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5377)
Let a and b be lvalues
of type const remove_reference_t<T>[.](#concept-2.sentence-1)
T and Cat model [three_way_comparable](#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")<T, Cat> only if
- [(2.1)](#concept-2.1)
(a <=> b == 0) == bool(a == b) is true,
- [(2.2)](#concept-2.2)
(a <=> b != 0) == bool(a != b) is true,
- [(2.3)](#concept-2.3)
((a <=> b) <=> 0) and (0 <=> (b <=> a)) are equal,
- [(2.4)](#concept-2.4)
(a <=> b < 0) == bool(a < b) is true,
- [(2.5)](#concept-2.5)
(a <=> b > 0) == bool(a > b) is true,
- [(2.6)](#concept-2.6)
(a <=> b <= 0) == bool(a <= b) is true,
- [(2.7)](#concept-2.7)
(a <=> b >= 0) == bool(a >= b) is true, and
- [(2.8)](#concept-2.8)
if Cat is convertible to strong_ordering, T models [totally_ordered](concept.totallyordered#concept:totally_ordered "18.5.5Concept totally_­ordered[concept.totallyordered]") ([[concept.totallyordered]](concept.totallyordered "18.5.5Concept totally_­ordered"))[.](#concept-2.sentence-2)
template<class T, class U, class Cat = partial_ordering>concept [three_way_comparable_with](#concept:three_way_comparable_with "17.12.4Concept three_­way_­comparable[cmp.concept]") =[three_way_comparable](#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")<T, Cat> &&[three_way_comparable](#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")<U, Cat> &&[*comparison-common-type-with*](concept.comparisoncommontype#concept:comparison-common-type-with "18.5.3Comparison common types[concept.comparisoncommontype]")<T, U> &&[three_way_comparable](#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")< common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>, Cat> &&[*weakly-equality-comparable-with*](concept.equalitycomparable#concept:weakly-equality-comparable-with "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<T, U> &&[*partially-ordered-with*](#concept:partially-ordered-with "17.12.4Concept three_­way_­comparable[cmp.concept]")<T, U> &&requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {{ t <=> u } -> [*compares-as*](#concept:compares-as "17.12.4Concept three_­way_­comparable[cmp.concept]")<Cat>; { u <=> t } -> [*compares-as*](#concept:compares-as "17.12.4Concept three_­way_­comparable[cmp.concept]")<Cat>; };
[3](#concept-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5418)
Let t and t2 be lvalues
denoting distinct equal objects
of types const remove_reference_t<T> andremove_cvref_t<T>, respectively, and
let u and u2 be lvalues denoting distinct equal objects
of types const remove_reference_t<U> andremove_cvref_t<U>, respectively[.](#concept-3.sentence-1)
Let C becommon_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>[.](#concept-3.sentence-2)
Let *CONVERT_TO_LVALUE*<C>(E) be defined
as in [[concepts.compare.general]](concepts.compare.general "18.5.1General")[.](#concept-3.sentence-3)
T, U, and Cat model [three_way_comparable_with](#concept:three_way_comparable_with "17.12.4Concept three_­way_­comparable[cmp.concept]")<T, U, Cat> only if
- [(3.1)](#concept-3.1)
t <=> u and u <=> t have the same domain,
- [(3.2)](#concept-3.2)
((t <=> u) <=> 0) and (0 <=> (u <=> t)) are equal,
- [(3.3)](#concept-3.3)
(t <=> u == 0) == bool(t == u) is true,
- [(3.4)](#concept-3.4)
(t <=> u != 0) == bool(t != u) is true,
- [(3.5)](#concept-3.5)
Cat(t <=> u) == Cat(*CONVERT_TO_LVALUE*<C>(t2) <=>*CONVERT_TO_LVALUE*<C>(u2)) is true,
- [(3.6)](#concept-3.6)
(t <=> u < 0) == bool(t < u) is true,
- [(3.7)](#concept-3.7)
(t <=> u > 0) == bool(t > u) is true,
- [(3.8)](#concept-3.8)
(t <=> u <= 0) == bool(t <= u) is true,
- [(3.9)](#concept-3.9)
(t <=> u >= 0) == bool(t >= u) is true, and
- [(3.10)](#concept-3.10)
if Cat is convertible to strong_ordering, T and U model [totally_ordered_with](concept.totallyordered#concept:totally_ordered_with "18.5.5Concept totally_­ordered[concept.totallyordered]")<T, U> ([[concept.totallyordered]](concept.totallyordered "18.5.5Concept totally_­ordered"))[.](#concept-3.sentence-4)
### [17.12.5](#result) Result of three-way comparison [[cmp.result]](cmp.result)
[1](#result-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5460)
The behavior of a program
that adds specializations for the compare_three_way_result template
defined in this subclause is undefined[.](#result-1.sentence-1)
[2](#result-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5465)
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[.](#result-2.sentence-1)
If the expression t <=> u is well-formed
when treated as an unevaluated operand ([[expr.context]](expr.context "7.2.3Context dependence")),
the member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") type denotes the type decltype(t <=> u)[.](#result-2.sentence-2)
Otherwise, there is no member type[.](#result-2.sentence-3)
### [17.12.6](#alg) Comparison algorithms [[cmp.alg]](cmp.alg)
[1](#alg-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5480)
The name strong_order denotes
a customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5Customization Point Object types"))[.](#alg-1.sentence-1)
Given subexpressions E and F,
the expression strong_order(E, F) is expression-equivalent ([[defns.expression.equivalent]](defns.expression.equivalent "3.22expression-equivalent")) to the following:
- [(1.1)](#alg-1.1)
If the decayed types of E and F differ, strong_order(E, F) is ill-formed[.](#alg-1.1.sentence-1)
- [(1.2)](#alg-1.2)
Otherwise, strong_ordering(strong_order(E, F)) if it is a well-formed expression
where the meaning of strong_order is established as-if by performing
argument-dependent lookup only ([[basic.lookup.argdep]](basic.lookup.argdep "6.5.4Argument-dependent name lookup"))[.](#alg-1.2.sentence-1)
- [(1.3)](#alg-1.3)
Otherwise, if the decayed type T of E is
a floating-point type,
yields a value of type strong_ordering that is consistent with the ordering
observed by T's comparison operators, and
if numeric_limits<T>::is_iec559 is true,
is additionally consistent with the totalOrder operation
as specified in ISO/IEC 60559[.](#alg-1.3.sentence-1)
- [(1.4)](#alg-1.4)
Otherwise, strong_ordering(compare_three_way()(E, F)) if it is a well-formed expression[.](#alg-1.4.sentence-1)
- [(1.5)](#alg-1.5)
Otherwise, strong_order(E, F) is ill-formed[.](#alg-1.5.sentence-1)
[*Note [1](#alg-note-1)*:
Ill-formed cases above result in substitution failure
when strong_order(E, F) appears in the immediate context
of a template instantiation[.](#alg-1.sentence-3)
— *end note*]
[2](#alg-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5518)
The name weak_order denotes
a customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5Customization Point Object types"))[.](#alg-2.sentence-1)
Given subexpressions E and F,
the expression weak_order(E, F) is expression-equivalent ([[defns.expression.equivalent]](defns.expression.equivalent "3.22expression-equivalent")) to the following:
- [(2.1)](#alg-2.1)
If the decayed types of E and F differ, weak_order(E, F) is ill-formed[.](#alg-2.1.sentence-1)
- [(2.2)](#alg-2.2)
Otherwise, weak_ordering(weak_order(E, F)) if it is a well-formed expression
where the meaning of weak_order is established as-if by performing
argument-dependent lookup only ([[basic.lookup.argdep]](basic.lookup.argdep "6.5.4Argument-dependent name lookup"))[.](#alg-2.2.sentence-1)
- [(2.3)](#alg-2.3)
Otherwise, if the decayed type T of E is a floating-point type,
yields a value of type weak_ordering that is consistent with the ordering
observed by T's comparison operators and strong_order, and
if numeric_limits<T>::is_iec559 is true,
is additionally consistent with the following equivalence classes,
ordered from lesser to greater:
* [(2.3.1)](#alg-2.3.1)
together, all negative NaN values;
* [(2.3.2)](#alg-2.3.2)
negative infinity;
* [(2.3.3)](#alg-2.3.3)
each normal negative value;
* [(2.3.4)](#alg-2.3.4)
each subnormal negative value;
* [(2.3.5)](#alg-2.3.5)
together, both zero values;
* [(2.3.6)](#alg-2.3.6)
each subnormal positive value;
* [(2.3.7)](#alg-2.3.7)
each normal positive value;
* [(2.3.8)](#alg-2.3.8)
positive infinity;
* [(2.3.9)](#alg-2.3.9)
together, all positive NaN values[.](#alg-2.3.sentence-1)
- [(2.4)](#alg-2.4)
Otherwise, weak_ordering(compare_three_way()(E, F)) if it is a well-formed expression[.](#alg-2.4.sentence-1)
- [(2.5)](#alg-2.5)
Otherwise, weak_ordering(strong_order(E, F)) if it is a well-formed expression[.](#alg-2.5.sentence-1)
- [(2.6)](#alg-2.6)
Otherwise, weak_order(E, F) is ill-formed[.](#alg-2.6.sentence-1)
[*Note [2](#alg-note-2)*:
Ill-formed cases above result in substitution failure
when weak_order(E, F) appears in the immediate context
of a template instantiation[.](#alg-2.sentence-3)
— *end note*]
[3](#alg-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5570)
The name partial_order denotes
a customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5Customization Point Object types"))[.](#alg-3.sentence-1)
Given subexpressions E and F,
the expression partial_order(E, F) is expression-equivalent ([[defns.expression.equivalent]](defns.expression.equivalent "3.22expression-equivalent")) to the following:
- [(3.1)](#alg-3.1)
If the decayed types of E and F differ, partial_order(E, F) is ill-formed[.](#alg-3.1.sentence-1)
- [(3.2)](#alg-3.2)
Otherwise, partial_ordering(partial_order(E, F)) if it is a well-formed expression
where the meaning of partial_order is established as-if by performing
argument-dependent lookup only ([[basic.lookup.argdep]](basic.lookup.argdep "6.5.4Argument-dependent name lookup"))[.](#alg-3.2.sentence-1)
- [(3.3)](#alg-3.3)
Otherwise, partial_ordering(compare_three_way()(E, F)) if it is a well-formed expression[.](#alg-3.3.sentence-1)
- [(3.4)](#alg-3.4)
Otherwise, partial_ordering(weak_order(E, F)) if it is a well-formed expression[.](#alg-3.4.sentence-1)
- [(3.5)](#alg-3.5)
Otherwise, partial_order(E, F) is ill-formed[.](#alg-3.5.sentence-1)
[*Note [3](#alg-note-3)*:
Ill-formed cases above result in substitution failure
when partial_order(E, F) appears in the immediate context
of a template instantiation[.](#alg-3.sentence-3)
— *end note*]
[4](#alg-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5602)
The name compare_strong_order_fallback denotes a customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5Customization Point Object types"))[.](#alg-4.sentence-1)
Given subexpressions E and F,
the expression compare_strong_order_fallback(E, F) is expression-equivalent ([[defns.expression.equivalent]](defns.expression.equivalent "3.22expression-equivalent")) to:
- [(4.1)](#alg-4.1)
If the decayed types of E and F differ, compare_strong_order_fallback(E, F) is ill-formed[.](#alg-4.1.sentence-1)
- [(4.2)](#alg-4.2)
Otherwise, strong_order(E, F) if it is a well-formed expression[.](#alg-4.2.sentence-1)
- [(4.3)](#alg-4.3)
Otherwise, if the expressions E == F and E < F are both well-formed and
each of decltype(E == F) and decltype(E < F) models [*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]"),E == F ? strong_ordering::equal : E < F ? strong_ordering::less : strong_ordering::greater except that E and F are evaluated only once[.](#alg-4.3.sentence-1)
- [(4.4)](#alg-4.4)
Otherwise, compare_strong_order_fallback(E, F) is ill-formed[.](#alg-4.4.sentence-1)
[*Note [4](#alg-note-4)*:
Ill-formed cases above result in substitution failure
when compare_strong_order_fallback(E, F) appears in the immediate context
of a template instantiation[.](#alg-4.sentence-3)
— *end note*]
[5](#alg-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5636)
The name compare_weak_order_fallback denotes
a customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5Customization Point Object types"))[.](#alg-5.sentence-1)
Given subexpressions E and F,
the expression compare_weak_order_fallback(E, F) is expression-equivalent ([[defns.expression.equivalent]](defns.expression.equivalent "3.22expression-equivalent")) to:
- [(5.1)](#alg-5.1)
If the decayed types of E and F differ, compare_weak_order_fallback(E, F) is ill-formed[.](#alg-5.1.sentence-1)
- [(5.2)](#alg-5.2)
Otherwise, weak_order(E, F) if it is a well-formed expression[.](#alg-5.2.sentence-1)
- [(5.3)](#alg-5.3)
Otherwise, if the expressions E == F and E < F are both well-formed and
each of decltype(E == F) and decltype(E < F) models [*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]"),E == F ? weak_ordering::equivalent : E < F ? weak_ordering::less : weak_ordering::greater except that E and F are evaluated only once[.](#alg-5.3.sentence-1)
- [(5.4)](#alg-5.4)
Otherwise, compare_weak_order_fallback(E, F) is ill-formed[.](#alg-5.4.sentence-1)
[*Note [5](#alg-note-5)*:
Ill-formed cases above result in substitution failure
when compare_weak_order_fallback(E, F) appears in the immediate context
of a template instantiation[.](#alg-5.sentence-3)
— *end note*]
[6](#alg-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5670)
The name compare_partial_order_fallback denotes
a customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5Customization Point Object types"))[.](#alg-6.sentence-1)
Given subexpressions E and F,
the expression compare_partial_order_fallback(E, F) is expression-equivalent ([[defns.expression.equivalent]](defns.expression.equivalent "3.22expression-equivalent")) to:
- [(6.1)](#alg-6.1)
If the decayed types of E and F differ, compare_partial_order_fallback(E, F) is ill-formed[.](#alg-6.1.sentence-1)
- [(6.2)](#alg-6.2)
Otherwise, partial_order(E, F) if it is a well-formed expression[.](#alg-6.2.sentence-1)
- [(6.3)](#alg-6.3)
Otherwise, if the expressions E == F, E < F, and F < E are all well-formed and
each of decltype(E == F), decltype(E < F), and decltype(F < E) models [*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]"),E == F ? partial_ordering::equivalent : E < F ? partial_ordering::less : F < E ? partial_ordering::greater : partial_ordering::unordered except that E and F are evaluated only once[.](#alg-6.3.sentence-1)
- [(6.4)](#alg-6.4)
Otherwise, compare_partial_order_fallback(E, F) is ill-formed[.](#alg-6.4.sentence-1)
[*Note [6](#alg-note-6)*:
Ill-formed cases above result in substitution failure
when compare_partial_order_fallback(E, F) appears in the immediate context
of a template instantiation[.](#alg-6.sentence-3)
— *end note*]
### [17.12.7](#compare.type) Type Ordering [[compare.type]](compare.type)
[1](#compare.type-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5708)
There is an implementation-defined total ordering of all types[.](#compare.type-1.sentence-1)
For any (possibly incomplete) types X and Y,
the expression *TYPE-ORDER*(X, Y) is a constant expression ([[expr.const]](expr.const "7.7Constant expressions"))
of type strong_ordering ([[cmp.strongord]](#strongord "17.12.2.4Class strong_­ordering"))[.](#compare.type-1.sentence-2)
Its value is strong_ordering::less if X precedes Y in this implementation-defined total order,strong_ordering::greater if Y precedes X, andstrong_ordering::equal if they are the same type[.](#compare.type-1.sentence-3)
[*Note [1](#compare.type-note-1)*:
int, const int and int& are different types[.](#compare.type-1.sentence-4)
— *end note*]
[*Note [2](#compare.type-note-2)*:
This ordering need not be consistent with the one induced by type_info::before[.](#compare.type-1.sentence-5)
— *end note*]
[*Note [3](#compare.type-note-3)*:
The ordering of TU-local types from different translation units is not observable,
because the necessary specialization of type_order is impossible to name[.](#compare.type-1.sentence-6)
— *end note*]
[🔗](#lib:type_order)
`template<class T, class U>
struct type_order;
`
[2](#compare.type-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5735)
The name type_order denotes a *Cpp17BinaryTypeTrait* ([[meta.rqmts]](meta.rqmts "21.3.2Requirements"))
with a base characteristic ofintegral_constant<strong_ordering, *TYPE-ORDER*(T, U)>[.](#compare.type-2.sentence-1)
[3](#compare.type-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/support.tex#L5740)
*Recommended practice*: The order should be lexicographical on parameter-type-lists and template argument lists[.](#compare.type-3.sentence-1)