[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*(E) be: - [(2.1)](#general-2.1) static_cast(as_const(E)) if that is a valid expression, and - [(2.2)](#general-2.2) static_cast(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.2 Boolean 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.14 Logical AND operator"), [[expr.log.or]](expr.log.or "7.6.15 Logical OR operator"), [[expr.unary.op]](expr.unary.op "7.6.2.2 Unary operators")) have the conventional semantics[.](#concept.booleantestable-1.sentence-1) [🔗](#concept:boolean-testable-impl) `template concept [boolean-testable-impl](#concept:boolean-testable-impl "18.5.2 Boolean testability [concept.booleantestable]") = [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_­to [concept.convertible]"); // 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.2 Boolean testability [concept.booleantestable]") only if - [(2.1)](#concept.booleantestable-2.1) either remove_cvref_t is not a class type, or a search for the names operator&& and operator|| in the scope of remove_cvref_t finds nothing; and - [(2.2)](#concept.booleantestable-2.2) argument-dependent lookup ([[basic.lookup.argdep]](basic.lookup.argdep "6.5.4 Argument-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.2 Boolean 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.2 Implicit 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.6 Deducing 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.2 Deducing 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.2 Boolean 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 struct C {}; templatevoid operator&&(C x, T y); templatevoid operator||(C> x, T y);} the declaration of Z​::​operator&& contains one key parameter, C 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.2 Boolean 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.4 Meaning 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.2 Boolean testability [concept.booleantestable]"), the && and || operators within the expressionsdeclval() && declval() anddeclval() || declval() resolve to the corresponding built-in operators[.](#concept.booleantestable-6.sentence-1) — *end note*] [🔗](#concept:boolean-testable) `template concept [boolean-testable](#concept:boolean-testable "18.5.2 Boolean testability [concept.booleantestable]") = // exposition only [boolean-testable-impl](#concept:boolean-testable-impl "18.5.2 Boolean testability [concept.booleantestable]") && requires(T&& t) { { !std::forward(t) } -> [boolean-testable-impl](#concept:boolean-testable-impl "18.5.2 Boolean 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.2 Boolean 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.3 Header synopsis")),int*, andbitset​::​reference ([[template.bitset]](template.bitset "22.9.2 Class template bitset")) model [*boolean-testable*](#concept:boolean-testable "18.5.2 Boolean 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> concept [comparison-common-type-with-impl](#concept:comparison-common-type-with-impl "18.5.3 Comparison common types [concept.comparisoncommontype]") = // exposition only [same_as](concept.same#concept:same_as "18.4.2 Concept same_­as [concept.same]"), common_reference_t> && requires { requires [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_­to [concept.convertible]") || [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_­to [concept.convertible]"); requires [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_­to [concept.convertible]") || [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_­to [concept.convertible]"); }; template concept [comparison-common-type-with](#concept:comparison-common-type-with "18.5.3 Comparison common types [concept.comparisoncommontype]") = // exposition only [comparison-common-type-with-impl](#concept:comparison-common-type-with-impl "18.5.3 Comparison common types [concept.comparisoncommontype]"), remove_cvref_t>; ` [1](#concept.comparisoncommontype-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/concepts.tex#L1007) Let C be common_reference_t[.](#concept.comparisoncommontype-1.sentence-1) Let t1 and t2 be equality-preserving expressions that are lvalues of type remove_cvref_t, and let u1 and u2 be equality-preserving expressions that are lvalues of type remove_cvref_t[.](#concept.comparisoncommontype-1.sentence-2) T and U model[*comparison-common-type-with*](#concept:comparison-common-type-with "18.5.3 Comparison common types [concept.comparisoncommontype]") only if - [(1.1)](#concept.comparisoncommontype-1.1) *CONVERT_TO_LVALUE*(t1) equals*CONVERT_TO_LVALUE*(t2) if and only if t1 equals t2, and - [(1.2)](#concept.comparisoncommontype-1.2) *CONVERT_TO_LVALUE*(u1) equals*CONVERT_TO_LVALUE*(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 concept [weakly-equality-comparable-with](#concept:weakly-equality-comparable-with "18.5.4 Concept equality_­comparable [concept.equalitycomparable]") = // exposition only requires(const remove_reference_t& t, const remove_reference_t& u) { { t == u } -> [boolean-testable](#concept:boolean-testable "18.5.2 Boolean testability [concept.booleantestable]"); { t != u } -> [boolean-testable](#concept:boolean-testable "18.5.2 Boolean testability [concept.booleantestable]"); { u == t } -> [boolean-testable](#concept:boolean-testable "18.5.2 Boolean testability [concept.booleantestable]"); { u != t } -> [boolean-testable](#concept:boolean-testable "18.5.2 Boolean 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 andconst remove_reference_t respectively[.](#concept.equalitycomparable-1.sentence-1) T and U model[*weakly-equality-comparable-with*](#concept:weakly-equality-comparable-with "18.5.4 Concept equality_­comparable [concept.equalitycomparable]") 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 concept [equality_comparable](#concept:equality_comparable "18.5.4 Concept equality_­comparable [concept.equalitycomparable]") = [weakly-equality-comparable-with](#concept:weakly-equality-comparable-with "18.5.4 Concept equality_­comparable [concept.equalitycomparable]"); ` [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.4 Concept equality_­comparable [concept.equalitycomparable]") only ifbool(a == b) is true when a is equal tob ([[concepts.equality]](concepts.equality "18.2 Equality 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 concept [equality_comparable_with](#concept:equality_comparable_with "18.5.4 Concept equality_­comparable [concept.equalitycomparable]") = [equality_comparable](#concept:equality_comparable "18.5.4 Concept equality_­comparable [concept.equalitycomparable]") && [equality_comparable](#concept:equality_comparable "18.5.4 Concept equality_­comparable [concept.equalitycomparable]") && [comparison-common-type-with](#concept:comparison-common-type-with "18.5.3 Comparison common types [concept.comparisoncommontype]") && [equality_comparable](#concept:equality_comparable "18.5.4 Concept equality_­comparable [concept.equalitycomparable]")< common_reference_t< const remove_reference_t&, const remove_reference_t&>> && [weakly-equality-comparable-with](#concept:weakly-equality-comparable-with "18.5.4 Concept equality_­comparable [concept.equalitycomparable]"); ` [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 andremove_cvref_t, respectively, let u and u2 be lvalues denoting distinct equal objects of types const remove_reference_t andremove_cvref_t, respectively, and let C be:common_reference_t&, const remove_reference_t&>T and U model[equality_comparable_with](#concept:equality_comparable_with "18.5.4 Concept equality_­comparable [concept.equalitycomparable]") only ifbool(t == u) == bool(*CONVERT_TO_LVALUE*(t2) == *CONVERT_TO_LVALUE*(u2)) ### [18.5.5](#concept.totallyordered) Concept totally_ordered [[concept.totallyordered]](concept.totallyordered) [🔗](#concept:totally_ordered) `template concept [totally_ordered](#concept:totally_ordered "18.5.5 Concept totally_­ordered [concept.totallyordered]") = [equality_comparable](#concept:equality_comparable "18.5.4 Concept equality_­comparable [concept.equalitycomparable]") && [partially-ordered-with](cmp.concept#concept:partially-ordered-with "17.12.4 Concept three_­way_­comparable [cmp.concept]"); ` [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[.](#concept.totallyordered-1.sentence-1) T models [totally_ordered](#concept:totally_ordered "18.5.5 Concept 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 concept [totally_ordered_with](#concept:totally_ordered_with "18.5.5 Concept totally_­ordered [concept.totallyordered]") = [totally_ordered](#concept:totally_ordered "18.5.5 Concept totally_­ordered [concept.totallyordered]") && [totally_ordered](#concept:totally_ordered "18.5.5 Concept totally_­ordered [concept.totallyordered]") && [equality_comparable_with](#concept:equality_comparable_with "18.5.4 Concept equality_­comparable [concept.equalitycomparable]") && [totally_ordered](#concept:totally_ordered "18.5.5 Concept totally_­ordered [concept.totallyordered]")< common_reference_t< const remove_reference_t&, const remove_reference_t&>> && [partially-ordered-with](cmp.concept#concept:partially-ordered-with "17.12.4 Concept three_­way_­comparable [cmp.concept]"); ` [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 andremove_cvref_t, respectively, let u and u2 be lvalues denoting distinct equal objects of types const remove_reference_t andremove_cvref_t, respectively, and let C be:common_reference_t&, const remove_reference_t&>T and U model[totally_ordered_with](#concept:totally_ordered_with "18.5.5 Concept totally_­ordered [concept.totallyordered]") only if - [(2.1)](#concept.totallyordered-2.1) bool(t < u) == bool(*CONVERT_TO_LVALUE*(t2) < *CONVERT_TO_LVALUE*(u2))[.](#concept.totallyordered-2.1.sentence-1) - [(2.2)](#concept.totallyordered-2.2) bool(t > u) == bool(*CONVERT_TO_LVALUE*(t2) > *CONVERT_TO_LVALUE*(u2))[.](#concept.totallyordered-2.2.sentence-1) - [(2.3)](#concept.totallyordered-2.3) bool(t <= u) == bool(*CONVERT_TO_LVALUE*(t2) <= *CONVERT_TO_LVALUE*(u2))[.](#concept.totallyordered-2.3.sentence-1) - [(2.4)](#concept.totallyordered-2.4) bool(t >= u) == bool(*CONVERT_TO_LVALUE*(t2) >= *CONVERT_TO_LVALUE*(u2))[.](#concept.totallyordered-2.4.sentence-1) - [(2.5)](#concept.totallyordered-2.5) bool(u < t) == bool(*CONVERT_TO_LVALUE*(u2) < *CONVERT_TO_LVALUE*(t2))[.](#concept.totallyordered-2.5.sentence-1) - [(2.6)](#concept.totallyordered-2.6) bool(u > t) == bool(*CONVERT_TO_LVALUE*(u2) > *CONVERT_TO_LVALUE*(t2))[.](#concept.totallyordered-2.6.sentence-1) - [(2.7)](#concept.totallyordered-2.7) bool(u <= t) == bool(*CONVERT_TO_LVALUE*(u2) <= *CONVERT_TO_LVALUE*(t2))[.](#concept.totallyordered-2.7.sentence-1) - [(2.8)](#concept.totallyordered-2.8) bool(u >= t) == bool(*CONVERT_TO_LVALUE*(u2) >= *CONVERT_TO_LVALUE*(t2))[.](#concept.totallyordered-2.8.sentence-1)