18 Concepts library [concepts]

18.5 Comparison concepts [concepts.compare]

18.5.1 General [concepts.compare.general]

Subclause [concepts.compare] describes concepts that establish relationships and orderings on values of possibly differing object types.
Given an expression E and a type C, let CONVERT_TO_LVALUE<C>(E) be:
  • static_cast<const C&>(as_const(E)) if that is a valid expression, and
  • static_cast<const C&>(std​::​move(E)) otherwise.

18.5.2 Boolean testability [concept.booleantestable]

The exposition-only boolean-testable concept specifies the requirements on expressions that are convertible to bool and for which the logical operators ([expr.log.and], [expr.log.or], [expr.unary.op]) have the conventional semantics.
template<class T> concept boolean-testable-impl = convertible_to<T, bool>; // exposition only
Let e be an expression such that decltype((e)) is T.
T models boolean-testable-impl only if:
  • 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
  • argument-dependent lookup ([basic.lookup.argdep]) for the names operator&& and operator|| with T as the only argument type finds no disqualifying declaration (defined below).
A disqualifying parameter is a function parameter whose declared type P
  • is not dependent on a template parameter, and there exists an implicit conversion sequence ([over.best.ics]) from e to P; or
  • is dependent on one or more template parameters, and either
    • P contains no template parameter that participates in template argument deduction ([temp.deduct.type]), or
    • template argument deduction using the rules for deducing template arguments in a function call ([temp.deduct.call]) and e as the argument succeeds.
A key parameter 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, and X contains at least one template parameter that participates in template argument deduction.
[Example 1: 
In namespace 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.
— end example]
A disqualifying declaration is
  • a (non-template) function declaration that contains at least one disqualifying parameter; or
  • a function template declaration that contains at least one disqualifying parameter, where
    • at least one disqualifying parameter is a key parameter; or
    • the declaration contains no key parameters; or
    • the declaration declares a function template to which no name is bound ([dcl.meaning]).
[Note 1: 
The intention is to ensure that given two types T1 and T2 that each model boolean-testable-impl, the && and || operators within the expressions declval<T1>() && declval<T2>() and declval<T1>() || declval<T2>() resolve to the corresponding built-in operators.
— end note]
template<class T> concept boolean-testable = // exposition only boolean-testable-impl<T> && requires(T&& t) { { !std::forward<T>(t) } -> boolean-testable-impl; };
Let e be an expression such that decltype((e)) is T.
T models boolean-testable only if bool(e) == !bool(!e).
[Example 2: 
The types bool, true_type ([meta.type.synop]), int*, and bitset<N>​::​reference ([template.bitset]) model boolean-testable.
— end example]

18.5.3 Comparison common types [concept.comparisoncommontype]

template<class T, class U, class C = common_reference_t<const T&, const U&>> concept comparison-common-type-with-impl = // exposition only same_as<common_reference_t<const T&, const U&>, common_reference_t<const U&, const T&>> && requires { requires convertible_to<const T&, const C&> || convertible_to<T, const C&>; requires convertible_to<const U&, const C&> || convertible_to<U, const C&>; }; template<class T, class U> concept comparison-common-type-with = // exposition only comparison-common-type-with-impl<remove_cvref_t<T>, remove_cvref_t<U>>;
Let C be common_reference_t<const T&, const U&>.
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>.
T and U model comparison-common-type-with<T, U> only if:
  • CONVERT_TO_LVALUE<C>(t1) equals CONVERT_TO_LVALUE<C>(t2) if and only if t1 equals t2, and
  • CONVERT_TO_LVALUE<C>(u1) equals CONVERT_TO_LVALUE<C>(u2) if and only if u1 equals u2

18.5.4 Concept equality_comparable [concept.equalitycomparable]

template<class T, class U> concept weakly-equality-comparable-with = // exposition only requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) { { t == u } -> boolean-testable; { t != u } -> boolean-testable; { u == t } -> boolean-testable; { u != t } -> boolean-testable; };
Given types T and U, let t and u be lvalues of types const remove_reference_t<T> and const remove_reference_t<U> respectively.
T and U model weakly-equality-comparable-with<T, U> only if
  • t == u, u == t, t != u, and u != t have the same domain.
  • bool(u == t) == bool(t == u).
  • bool(t != u) == !bool(t == u).
  • bool(u != t) == bool(t != u).
Let a and b be objects of type T.
T models equality_comparable only if bool(a == b) is true when a is equal to b ([concepts.equality]), and false otherwise.
[Note 1: 
The requirement that the expression a == b is equality-preserving implies that == is transitive and symmetric.
— end note]
template<class T, class U> concept equality_comparable_with = equality_comparable<T> && equality_comparable<U> && comparison-common-type-with<T, U> && equality_comparable< common_reference_t< const remove_reference_t<T>&, const remove_reference_t<U>&>> && weakly-equality-comparable-with<T, U>;
Given types T and U, let t and t2 be lvalues denoting distinct equal objects of types const remove_reference_t<T> and remove_cvref_t<T>, respectively, let u and u2 be lvalues denoting distinct equal objects of types const remove_reference_t<U> and remove_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<T, U> only if bool(t == u) == bool(CONVERT_TO_LVALUE<C>(t2) == CONVERT_TO_LVALUE<C>(u2))

18.5.5 Concept totally_ordered [concept.totallyordered]

template<class T> concept totally_ordered = equality_comparable<T> && partially-ordered-with<T, T>;
Given a type T, let a, b, and c be lvalues of type const remove_reference_t<T>.
T models totally_ordered only if
  • Exactly one of bool(a < b), bool(a > b), or bool(a == b) is true.
  • If bool(a < b) and bool(b < c), then bool(a < c).
  • bool(a <= b) == !bool(b < a).
  • bool(a >= b) == !bool(a < b).
template<class T, class U> concept totally_ordered_with = totally_ordered<T> && totally_ordered<U> && equality_comparable_with<T, U> && totally_ordered< common_reference_t< const remove_reference_t<T>&, const remove_reference_t<U>&>> && partially-ordered-with<T, U>;
Given types T and U, let t and t2 be lvalues denoting distinct equal objects of types const remove_reference_t<T> and remove_cvref_t<T>, respectively, let u and u2 be lvalues denoting distinct equal objects of types const remove_reference_t<U> and remove_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<T, U> only if
  • bool(t < u) == bool(CONVERT_TO_LVALUE<C>(t2) < CONVERT_TO_LVALUE<C>(u2)).
  • bool(t > u) == bool(CONVERT_TO_LVALUE<C>(t2) > CONVERT_TO_LVALUE<C>(u2)).
  • bool(t <= u) == bool(CONVERT_TO_LVALUE<C>(t2) <= CONVERT_TO_LVALUE<C>(u2)).
  • bool(t >= u) == bool(CONVERT_TO_LVALUE<C>(t2) >= CONVERT_TO_LVALUE<C>(u2)).
  • bool(u < t) == bool(CONVERT_TO_LVALUE<C>(u2) < CONVERT_TO_LVALUE<C>(t2)).
  • bool(u > t) == bool(CONVERT_TO_LVALUE<C>(u2) > CONVERT_TO_LVALUE<C>(t2)).
  • bool(u <= t) == bool(CONVERT_TO_LVALUE<C>(u2) <= CONVERT_TO_LVALUE<C>(t2)).
  • bool(u >= t) == bool(CONVERT_TO_LVALUE<C>(u2) >= CONVERT_TO_LVALUE<C>(t2)).