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

395 lines
20 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.

[concepts.compare]
# 18 Concepts library [[concepts]](./#concepts)
## 18.5 Comparison concepts [concepts.compare]
### [18.5.1](#general) General [[concepts.compare.general]](concepts.compare.general)
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L843)
Subclause [concepts.compare] describes concepts that establish relationships and orderings
on values of possibly differing object types[.](#general-1.sentence-1)
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L847)
Given an expression E and a type C,
let *CONVERT_TO_LVALUE*<C>(E) be:
- [(2.1)](#general-2.1)
static_cast<const C&>(as_const(E)) if that is a valid expression, and
- [(2.2)](#general-2.2)
static_cast<const C&>(std::move(E)) otherwise[.](#general-2.sentence-1)
### [18.5.2](#concept.booleantestable) Boolean testability [[concept.booleantestable]](concept.booleantestable)
[1](#concept.booleantestable-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L859)
The exposition-only [*boolean-testable*](#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]") concept
specifies the requirements on expressions
that are convertible to bool and
for which the logical operators ([[expr.log.and]](expr.log.and "7.6.14Logical AND operator"), [[expr.log.or]](expr.log.or "7.6.15Logical OR operator"), [[expr.unary.op]](expr.unary.op "7.6.2.2Unary operators"))
have the conventional semantics[.](#concept.booleantestable-1.sentence-1)
[🔗](#concept:boolean-testable-impl)
`template<class T>
concept [boolean-testable-impl](#concept:boolean-testable-impl "18.5.2Boolean testability[concept.booleantestable]") = [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<T, bool>; // exposition only
`
[2](#concept.booleantestable-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L871)
Let e be an expression such thatdecltype((e)) is T[.](#concept.booleantestable-2.sentence-1)
T models [*boolean-testable-impl*](#concept:boolean-testable-impl "18.5.2Boolean testability[concept.booleantestable]") only if
- [(2.1)](#concept.booleantestable-2.1)
either remove_cvref_t<T> is not a class type, or
a search for the names operator&& and operator|| in the scope of remove_cvref_t<T> finds nothing; and
- [(2.2)](#concept.booleantestable-2.2)
argument-dependent lookup ([[basic.lookup.argdep]](basic.lookup.argdep "6.5.4Argument-dependent name lookup"))
for the names operator&& and operator|| with T as the only argument type
finds no disqualifying declaration (defined below)[.](#concept.booleantestable-2.sentence-2)
[3](#concept.booleantestable-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L889)
A [*disqualifying parameter*](#def:parameter,disqualifying "18.5.2Boolean testability[concept.booleantestable]") is a function parameter whose declared type P
- [(3.1)](#concept.booleantestable-3.1)
is not dependent on a template parameter, and
there exists an implicit conversion sequence ([[over.best.ics]](over.best.ics "12.2.4.2Implicit conversion sequences"))
from e to P; or
- [(3.2)](#concept.booleantestable-3.2)
is dependent on one or more template parameters, and either
* [(3.2.1)](#concept.booleantestable-3.2.1)
P contains no template parameter that
participates in template argument deduction ([[temp.deduct.type]](temp.deduct.type "13.10.3.6Deducing template arguments from a type")), or
* [(3.2.2)](#concept.booleantestable-3.2.2)
template argument deduction
using the rules for deducing template arguments
in a function call ([[temp.deduct.call]](temp.deduct.call "13.10.3.2Deducing template arguments from a function call")) ande as the argument succeeds[.](#concept.booleantestable-3.sentence-1)
[4](#concept.booleantestable-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L912)
A [*key parameter*](#def:parameter,key "18.5.2Boolean testability[concept.booleantestable]") of a function template D is a function parameter of type cv X or reference thereto,
where X names a specialization of a class template that
has the same innermost enclosing non-inline namespace as D, andX contains at least one template parameter that
participates in template argument deduction[.](#concept.booleantestable-4.sentence-1)
[*Example [1](#concept.booleantestable-example-1)*:
Innamespace Z {template<class> struct C {}; template<class T>void operator&&(C<T> x, T y); template<class T>void operator||(C<type_identity_t<T>> x, T y);} the declaration of Z::operator&& contains one key parameter, C<T> x, and
the declaration of Z::operator|| contains no key parameters[.](#concept.booleantestable-4.sentence-2)
— *end example*]
[5](#concept.booleantestable-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L937)
A [*disqualifying declaration*](#def:declaration,disqualifying "18.5.2Boolean testability[concept.booleantestable]") is
- [(5.1)](#concept.booleantestable-5.1)
a (non-template) function declaration that
contains at least one disqualifying parameter; or
- [(5.2)](#concept.booleantestable-5.2)
a function template declaration that
contains at least one disqualifying parameter, where
* [(5.2.1)](#concept.booleantestable-5.2.1)
at least one disqualifying parameter is a key parameter; or
* [(5.2.2)](#concept.booleantestable-5.2.2)
the declaration contains no key parameters; or
* [(5.2.3)](#concept.booleantestable-5.2.3)
the declaration declares a function template
to which no name is bound ([[dcl.meaning]](dcl.meaning "9.3.4Meaning of declarators"))[.](#concept.booleantestable-5.sentence-1)
[6](#concept.booleantestable-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L955)
[*Note [1](#concept.booleantestable-note-1)*:
The intention is to ensure that
given two types T1 and T2 that each model [*boolean-testable-impl*](#concept:boolean-testable-impl "18.5.2Boolean testability[concept.booleantestable]"),
the && and || operators within the expressionsdeclval<T1>() && declval<T2>() anddeclval<T1>() || declval<T2>() resolve to the corresponding built-in operators[.](#concept.booleantestable-6.sentence-1)
— *end note*]
[🔗](#concept:boolean-testable)
`template<class T>
concept [boolean-testable](#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]") = // exposition only
[boolean-testable-impl](#concept:boolean-testable-impl "18.5.2Boolean testability[concept.booleantestable]")<T> && requires(T&& t) {
{ !std::forward<T>(t) } -> [boolean-testable-impl](#concept:boolean-testable-impl "18.5.2Boolean testability[concept.booleantestable]");
};
`
[7](#concept.booleantestable-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L974)
Let e be an expression such thatdecltype((e)) is T[.](#concept.booleantestable-7.sentence-1)
T models [*boolean-testable*](#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]") only ifbool(e) == !bool(!e)[.](#concept.booleantestable-7.sentence-2)
[8](#concept.booleantestable-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L980)
[*Example [2](#concept.booleantestable-example-2)*:
The typesbool,true_type ([[meta.type.synop]](meta.type.synop "21.3.3Header <type_­traits> synopsis")),int*, andbitset<N>::reference ([[template.bitset]](template.bitset "22.9.2Class template bitset"))
model [*boolean-testable*](#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]")[.](#concept.booleantestable-8.sentence-1)
— *end example*]
### [18.5.3](#concept.comparisoncommontype) Comparison common types [[concept.comparisoncommontype]](concept.comparisoncommontype)
[🔗](#concept.comparisoncommontype-itemdecl:1)
`template<class T, class U, class C = common_reference_t<const T&, const U&>>
concept [comparison-common-type-with-impl](#concept:comparison-common-type-with-impl "18.5.3Comparison common types[concept.comparisoncommontype]") = // exposition only
[same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<common_reference_t<const T&, const U&>,
common_reference_t<const U&, const T&>> &&
requires {
requires [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<const T&, const C&> || [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<T, const C&>;
requires [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<const U&, const C&> || [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<U, const C&>;
};
template<class T, class U>
concept [comparison-common-type-with](#concept:comparison-common-type-with "18.5.3Comparison common types[concept.comparisoncommontype]") = // exposition only
[comparison-common-type-with-impl](#concept:comparison-common-type-with-impl "18.5.3Comparison common types[concept.comparisoncommontype]")<remove_cvref_t<T>, remove_cvref_t<U>>;
`
[1](#concept.comparisoncommontype-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L1007)
Let C be common_reference_t<const T&, const U&>[.](#concept.comparisoncommontype-1.sentence-1)
Let t1 and t2 be equality-preserving expressions
that are lvalues of type remove_cvref_t<T>, and
let u1 and u2 be equality-preserving expressions
that are lvalues of type remove_cvref_t<U>[.](#concept.comparisoncommontype-1.sentence-2)
T and U model[*comparison-common-type-with*](#concept:comparison-common-type-with "18.5.3Comparison common types[concept.comparisoncommontype]")<T, U> only if
- [(1.1)](#concept.comparisoncommontype-1.1)
*CONVERT_TO_LVALUE*<C>(t1) equals*CONVERT_TO_LVALUE*<C>(t2) if and only if t1 equals t2, and
- [(1.2)](#concept.comparisoncommontype-1.2)
*CONVERT_TO_LVALUE*<C>(u1) equals*CONVERT_TO_LVALUE*<C>(u2) if and only if u1 equals u2
### [18.5.4](#concept.equalitycomparable) Concept equality_comparable [[concept.equalitycomparable]](concept.equalitycomparable)
[🔗](#concept:weakly-equality-comparable-with)
`template<class T, class U>
concept [weakly-equality-comparable-with](#concept:weakly-equality-comparable-with "18.5.4Concept equality_­comparable[concept.equalitycomparable]") = // exposition only
requires(const remove_reference_t<T>& t,
const remove_reference_t<U>& u) {
{ t == u } -> [boolean-testable](#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]");
{ t != u } -> [boolean-testable](#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]");
{ u == t } -> [boolean-testable](#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]");
{ u != t } -> [boolean-testable](#concept:boolean-testable "18.5.2Boolean testability[concept.booleantestable]");
};
`
[1](#concept.equalitycomparable-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L1041)
Given types T and U,
let t and u be lvalues of typesconst remove_reference_t<T> andconst remove_reference_t<U> respectively[.](#concept.equalitycomparable-1.sentence-1)
T and U model[*weakly-equality-comparable-with*](#concept:weakly-equality-comparable-with "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<T, U> only if
- [(1.1)](#concept.equalitycomparable-1.1)
t == u, u == t, t != u, and u != t have the same domain[.](#concept.equalitycomparable-1.1.sentence-1)
- [(1.2)](#concept.equalitycomparable-1.2)
bool(u == t) == bool(t == u)[.](#concept.equalitycomparable-1.2.sentence-1)
- [(1.3)](#concept.equalitycomparable-1.3)
bool(t != u) == !bool(t == u)[.](#concept.equalitycomparable-1.3.sentence-1)
- [(1.4)](#concept.equalitycomparable-1.4)
bool(u != t) == bool(t != u)[.](#concept.equalitycomparable-1.4.sentence-1)
[🔗](#concept:equality_comparable)
`template<class T>
concept [equality_comparable](#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]") = [weakly-equality-comparable-with](#concept:weakly-equality-comparable-with "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<T, T>;
`
[2](#concept.equalitycomparable-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L1063)
Let a and b be objects of type T[.](#concept.equalitycomparable-2.sentence-1)
T models [equality_comparable](#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]") only ifbool(a == b) is true when a is equal tob ([[concepts.equality]](concepts.equality "18.2Equality preservation")), and false otherwise[.](#concept.equalitycomparable-2.sentence-2)
[3](#concept.equalitycomparable-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L1069)
[*Note [1](#concept.equalitycomparable-note-1)*:
The requirement that the expression a == b is equality-preserving
implies that == is transitive and symmetric[.](#concept.equalitycomparable-3.sentence-1)
— *end note*]
[🔗](#concept:equality_comparable_with)
`template<class T, class U>
concept [equality_comparable_with](#concept:equality_comparable_with "18.5.4Concept equality_­comparable[concept.equalitycomparable]") =
[equality_comparable](#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<T> && [equality_comparable](#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<U> &&
[comparison-common-type-with](#concept:comparison-common-type-with "18.5.3Comparison common types[concept.comparisoncommontype]")<T, U> &&
[equality_comparable](#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<
common_reference_t<
const remove_reference_t<T>&,
const remove_reference_t<U>&>> &&
[weakly-equality-comparable-with](#concept:weakly-equality-comparable-with "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<T, U>;
`
[4](#concept.equalitycomparable-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L1089)
Given types T and U,
let t and t2 be lvalues
denoting distinct equal objects of types const remove_reference_t<T> andremove_cvref_t<T>, respectively,
let u and u2 be lvalues
denoting distinct equal objects of types const remove_reference_t<U> andremove_cvref_t<U>, respectively, and
let C be:common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>T and U model[equality_comparable_with](#concept:equality_comparable_with "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<T, U> only ifbool(t == u) == bool(*CONVERT_TO_LVALUE*<C>(t2) == *CONVERT_TO_LVALUE*<C>(u2))
### [18.5.5](#concept.totallyordered) Concept totally_ordered [[concept.totallyordered]](concept.totallyordered)
[🔗](#concept:totally_ordered)
`template<class T>
concept [totally_ordered](#concept:totally_ordered "18.5.5Concept totally_­ordered[concept.totallyordered]") =
[equality_comparable](#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<T> && [partially-ordered-with](cmp.concept#concept:partially-ordered-with "17.12.4Concept three_­way_­comparable[cmp.concept]")<T, T>;
`
[1](#concept.totallyordered-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L1117)
Given a type T, let a, b, and c be
lvalues of type const remove_reference_t<T>[.](#concept.totallyordered-1.sentence-1)
T models [totally_ordered](#concept:totally_ordered "18.5.5Concept totally_­ordered[concept.totallyordered]") only if
- [(1.1)](#concept.totallyordered-1.1)
Exactly one of bool(a < b), bool(a > b), or bool(a == b) is true[.](#concept.totallyordered-1.1.sentence-1)
- [(1.2)](#concept.totallyordered-1.2)
If bool(a < b) and bool(b < c), then bool(a < c)[.](#concept.totallyordered-1.2.sentence-1)
- [(1.3)](#concept.totallyordered-1.3)
bool(a <= b) == !bool(b < a)[.](#concept.totallyordered-1.3.sentence-1)
- [(1.4)](#concept.totallyordered-1.4)
bool(a >= b) == !bool(a < b)[.](#concept.totallyordered-1.4.sentence-1)
[🔗](#concept:totally_ordered_with)
`template<class T, class U>
concept [totally_ordered_with](#concept:totally_ordered_with "18.5.5Concept totally_­ordered[concept.totallyordered]") =
[totally_ordered](#concept:totally_ordered "18.5.5Concept totally_­ordered[concept.totallyordered]")<T> && [totally_ordered](#concept:totally_ordered "18.5.5Concept totally_­ordered[concept.totallyordered]")<U> &&
[equality_comparable_with](#concept:equality_comparable_with "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<T, U> &&
[totally_ordered](#concept:totally_ordered "18.5.5Concept totally_­ordered[concept.totallyordered]")<
common_reference_t<
const remove_reference_t<T>&,
const remove_reference_t<U>&>> &&
[partially-ordered-with](cmp.concept#concept:partially-ordered-with "17.12.4Concept three_­way_­comparable[cmp.concept]")<T, U>;
`
[2](#concept.totallyordered-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L1144)
Given types T and U,
let t and t2 be lvalues
denoting distinct equal objects of types const remove_reference_t<T> andremove_cvref_t<T>, respectively,
let u and u2 be lvalues
denoting distinct equal objects of types const remove_reference_t<U> andremove_cvref_t<U>, respectively, and
let C be:common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>T and U model[totally_ordered_with](#concept:totally_ordered_with "18.5.5Concept totally_­ordered[concept.totallyordered]")<T, U> only if
- [(2.1)](#concept.totallyordered-2.1)
bool(t < u) == bool(*CONVERT_TO_LVALUE*<C>(t2) < *CONVERT_TO_LVALUE*<C>(u2))[.](#concept.totallyordered-2.1.sentence-1)
- [(2.2)](#concept.totallyordered-2.2)
bool(t > u) == bool(*CONVERT_TO_LVALUE*<C>(t2) > *CONVERT_TO_LVALUE*<C>(u2))[.](#concept.totallyordered-2.2.sentence-1)
- [(2.3)](#concept.totallyordered-2.3)
bool(t <= u) == bool(*CONVERT_TO_LVALUE*<C>(t2) <= *CONVERT_TO_LVALUE*<C>(u2))[.](#concept.totallyordered-2.3.sentence-1)
- [(2.4)](#concept.totallyordered-2.4)
bool(t >= u) == bool(*CONVERT_TO_LVALUE*<C>(t2) >= *CONVERT_TO_LVALUE*<C>(u2))[.](#concept.totallyordered-2.4.sentence-1)
- [(2.5)](#concept.totallyordered-2.5)
bool(u < t) == bool(*CONVERT_TO_LVALUE*<C>(u2) < *CONVERT_TO_LVALUE*<C>(t2))[.](#concept.totallyordered-2.5.sentence-1)
- [(2.6)](#concept.totallyordered-2.6)
bool(u > t) == bool(*CONVERT_TO_LVALUE*<C>(u2) > *CONVERT_TO_LVALUE*<C>(t2))[.](#concept.totallyordered-2.6.sentence-1)
- [(2.7)](#concept.totallyordered-2.7)
bool(u <= t) == bool(*CONVERT_TO_LVALUE*<C>(u2) <= *CONVERT_TO_LVALUE*<C>(t2))[.](#concept.totallyordered-2.7.sentence-1)
- [(2.8)](#concept.totallyordered-2.8)
bool(u >= t) == bool(*CONVERT_TO_LVALUE*<C>(u2) >= *CONVERT_TO_LVALUE*<C>(t2))[.](#concept.totallyordered-2.8.sentence-1)