17 Concepts library [concepts]

17.1 General [concepts.general]

This Clause describes library components that C++ programs may use to perform compile-time validation of template arguments and perform function dispatch based on properties of types.
The purpose of these concepts is to establish a foundation for equational reasoning in programs.
The following subclauses describe language-related concepts, comparison concepts, object concepts, and callable concepts as summarized in Table 36.
Table 36 — Fundamental concepts library summary
Subclause
Header(s)
Language-related concepts
<concepts>
Comparison concepts
Object concepts
Callable concepts

17.2 Equality preservation [concepts.equality]

An expression is equality-preserving if, given equal inputs, the expression results in equal outputs.
The inputs to an expression are the set of the expression's operands.
The output of an expression is the expression's result and all operands modified by the expression.
Not all input values need be valid for a given expression; e.g., for integers a and b, the expression a / b is not well-defined when b is 0.
This does not preclude the expression a / b being equality-preserving.
The domain of an expression is the set of input values for which the expression is required to be well-defined.
Expressions required by this document to be equality-preserving are further required to be stable: two evaluations of such an expression with the same input objects are required to have equal outputs absent any explicit intervening modification of those input objects.
[Note
:
This requirement allows generic code to reason about the current values of objects based on knowledge of the prior values as observed via equality-preserving expressions.
It effectively forbids spontaneous changes to an object, changes to an object from another thread of execution, changes to an object as side effects of non-modifying expressions, and changes to an object as side effects of modifying a distinct object if those changes could be observable to a library function via an equality-preserving expression that is required to be valid for that object.
end note
]
Expressions declared in a requires-expression in this document are required to be equality-preserving, except for those annotated with the comment “not required to be equality-preserving.
” An expression so annotated may be equality-preserving, but is not required to be so.
An expression that may alter the value of one or more of its inputs in a manner observable to equality-preserving expressions is said to modify those inputs.
This document uses a notational convention to specify which expressions declared in a requires-expression modify which inputs: except where otherwise specified, an expression operand that is a non-constant lvalue or rvalue may be modified.
Operands that are constant lvalues or rvalues are required to not be modified.
Where a requires-expression declares an expression that is non-modifying for some constant lvalue operand, additional variations of that expression that accept a non-constant lvalue or (possibly constant) rvalue for the given operand are also required except where such an expression variation is explicitly required with differing semantics.
These implicit expression variations are required to meet the semantic requirements of the declared expression.
The extent to which an implementation validates the syntax of the variations is unspecified.
[Example
:
template<class T> concept C = requires(T a, T b, const T c, const T d) {
  c == d;           // #1
  a = std::move(b); // #2
  a = c;            // #3
};
For the above example:
  • Expression #1 does not modify either of its operands, #2 modifies both of its operands, and #3 modifies only its first operand a.
  • Expression #1 implicitly requires additional expression variations that meet the requirements for c == d (including non-modification), as if the expressions
                                                c  ==           b;
              c  == std::move(d);               c  == std::move(b);
    std::move(c) ==           d;      std::move(c) ==           b;
    std::move(c) == std::move(d);     std::move(c) == std::move(b);
    
              a  ==           d;                a  ==           b;
              a  == std::move(d);               a  == std::move(b);
    std::move(a) ==           d;      std::move(a) ==           b;
    std::move(a) == std::move(d);     std::move(a) == std::move(b);
    
    had been declared as well.
  • Expression #3 implicitly requires additional expression variations that meet the requirements for a = c (including non-modification of the second operand), as if the expressions a = b and a = std::move(c) had been declared.
    Expression #3 does not implicitly require an expression variation with a non-constant rvalue second operand, since expression #2 already specifies exactly such an expression explicitly.
end example
]
[Example
:
The following type T meets the explicitly stated syntactic requirements of concept C above but does not meet the additional implicit requirements:
struct T {
  bool operator==(const T&) const { return true; }
  bool operator==(T&) = delete;
};
T fails to meet the implicit requirements of C, so C<T> is not satisfied.
Since implementations are not required to validate the syntax of implicit requirements, it is unspecified whether an implementation diagnoses as ill-formed a program that requires C<T>.
end example
]

17.3 Header <concepts> synopsis [concepts.syn]

namespace std {
  // [concepts.lang], language-related concepts
  // [concept.same], concept Same
  template<class T, class U>
    concept Same = see below;

  // [concept.derivedfrom], concept DerivedFrom
  template<class Derived, class Base>
    concept DerivedFrom = see below;

  // [concept.convertibleto], concept ConvertibleTo
  template<class From, class To>
    concept ConvertibleTo = see below;

  // [concept.commonref], concept CommonReference
  template<class T, class U>
    concept CommonReference = see below;

  // [concept.common], concept Common
  template<class T, class U>
    concept Common = see below;

  // [concepts.integral], integral concepts
  template<class T>
    concept Integral = see below;
  template<class T>
    concept SignedIntegral = see below;
  template<class T>
    concept UnsignedIntegral = see below;

  // [concept.assignable], concept Assignable
  template<class LHS, class RHS>
    concept Assignable = see below;

  // [concept.swappable], concept Swappable
  template<class T>
    concept Swappable = see below;
  template<class T, class U>
    concept SwappableWith = see below;

  // [concept.destructible], concept Destructible
  template<class T>
    concept Destructible = see below;

  // [concept.constructible], concept Constructible
  template<class T, class... Args>
    concept Constructible = see below;

  // [concept.defaultconstructible], concept DefaultConstructible
  template<class T>
    concept DefaultConstructible = see below;

  // [concept.moveconstructible], concept MoveConstructible
  template<class T>
    concept MoveConstructible = see below;

  // [concept.copyconstructible], concept CopyConstructible
  template<class T>
    concept CopyConstructible = see below;

  // [concepts.compare], comparison concepts
  // [concept.boolean], concept Boolean
  template<class B>
    concept Boolean = see below;

  // [concept.equalitycomparable], concept EqualityComparable
  template<class T>
    concept EqualityComparable = see below;
  template<class T, class U>
    concept EqualityComparableWith = see below;

  // [concept.stricttotallyordered], concept StrictTotallyOrdered
  template<class T>
    concept StrictTotallyOrdered = see below;
  template<class T, class U>
    concept StrictTotallyOrderedWith = see below;

  // [concepts.object], object concepts
  template<class T>
    concept Movable = see below;
  template<class T>
    concept Copyable = see below;
  template<class T>
    concept Semiregular = see below;
  template<class T>
    concept Regular = see below;

  // [concepts.callable], callable concepts
  // [concept.invocable], concept Invocable
  template<class F, class... Args>
    concept Invocable = see below;

  // [concept.regularinvocable], concept RegularInvocable
  template<class F, class... Args>
    concept RegularInvocable = see below;

  // [concept.predicate], concept Predicate
  template<class F, class... Args>
    concept Predicate = see below;

  // [concept.relation], concept Relation
  template<class R, class T, class U>
    concept Relation = see below;

  // [concept.strictweakorder], concept StrictWeakOrder
  template<class R, class T, class U>
    concept StrictWeakOrder = see below;
}

17.4 Language-related concepts [concepts.lang]

17.4.1 General [concepts.lang.general]

This subclause contains the definition of concepts corresponding to language features.
These concepts express relationships between types, type classifications, and fundamental type properties.

17.4.2 Concept Same [concept.same]

template<class T, class U> concept Same = is_same_v<T, U>;
Same<T, U> subsumes Same<U, T> and vice versa.

17.4.3 Concept DerivedFrom [concept.derivedfrom]

template<class Derived, class Base> concept DerivedFrom = is_base_of_v<Base, Derived> && is_convertible_v<const volatile Derived*, const volatile Base*>;
[Note
:
DerivedFrom<Derived, Base> is satisfied if and only if Derived is publicly and unambiguously derived from Base, or Derived and Base are the same class type ignoring cv-qualifiers.
end note
]

17.4.4 Concept ConvertibleTo [concept.convertibleto]

The ConvertibleTo concept requires an expression of a particular type and value category to be both implicitly and explicitly convertible to some other type.
The implicit and explicit conversions are required to produce equal results.
template<class From, class To> concept ConvertibleTo = is_convertible_v<From, To> && requires(From (&f)()) { static_cast<To>(f()); };
Let test be the invented function:
To test(From (&f)()) {
  return f();
}
and let f be a function with no arguments and return type From such that f() is equality-preserving.
ConvertibleTo<From, To> is satisfied only if:
  • To is not an object or reference-to-object type, or static_­cast<To>(f()) is equal to test(f).
  • From is not a reference-to-object type, or
    • If From is an rvalue reference to a non const-qualified type, the resulting state of the object referenced by f() after either above expression is valid but unspecified ([lib.types.movedfrom]).
    • Otherwise, the object referred to by f() is not modified by either above expression.

17.4.5 Concept CommonReference [concept.commonref]

For two types T and U, if common_­reference_­t<T, U> is well-formed and denotes a type C such that both ConvertibleTo<T, C> and ConvertibleTo<U, C> are satisfied, then T and U share a common reference type, C.
[Note
:
C could be the same as T, or U, or it could be a different type.
C may be a reference type.
end note
]
template<class T, class U> concept CommonReference = Same<common_reference_t<T, U>, common_reference_t<U, T>> && ConvertibleTo<T, common_reference_t<T, U>> && ConvertibleTo<U, common_reference_t<T, U>>;
Let C be common_­reference_­t<T, U>.
Let t be a function whose return type is T, and let u be a function whose return type is U.
CommonReference<T, U> is satisfied only if:
  • C(t()) equals C(t()) if and only if t() is an equality-preserving expression ([concepts.equality]).
  • C(u()) equals C(u()) if and only if u() is an equality-preserving expression.
[Note
:
Users can customize the behavior of CommonReference by specializing the basic_­common_­reference class template ([meta.trans.other]).
end note
]

17.4.6 Concept Common [concept.common]

If T and U can both be explicitly converted to some third type, C, then T and U share a common type, C.
[Note
:
C could be the same as T, or U, or it could be a different type.
C might not be unique.
end note
]
template<class T, class U> concept Common = Same<common_type_t<T, U>, common_type_t<U, T>> && ConvertibleTo<T, common_type_t<T, U>> && ConvertibleTo<U, common_type_t<T, U>> && CommonReference< add_lvalue_reference_t<const T>, add_lvalue_reference_t<const U>> && CommonReference< add_lvalue_reference_t<common_type_t<T, U>>, common_reference_t< add_lvalue_reference_t<const T>, add_lvalue_reference_t<const U>>>;
Let C be common_­type_­t<T, U>.
Let t be a function whose return type is T, and let u be a function whose return type is U.
Common<T, U> is satisfied only if:
[Note
:
Users can customize the behavior of Common by specializing the common_­type class template ([meta.trans.other]).
end note
]

17.4.7 Integral concepts [concepts.integral]

template<class T> concept Integral = is_integral_v<T>; template<class T> concept SignedIntegral = Integral<T> && is_signed_v<T>; template<class T> concept UnsignedIntegral = Integral<T> && !SignedIntegral<T>;
[Note
:
SignedIntegral<T> can be satisfied even by types that are not signed integral types ([basic.fundamental]); for example, char.
end note
]
[Note
:
UnsignedIntegral<T> can be satisfied even by types that are not unsigned integral types ([basic.fundamental]); for example, bool.
end note
]

17.4.8 Concept Assignable [concept.assignable]

template<class LHS, class RHS> concept Assignable = is_lvalue_reference_v<LHS> && CommonReference<const remove_reference_t<LHS>&, const remove_reference_t<RHS>&> && requires(LHS lhs, RHS&& rhs) { lhs = std::forward<RHS>(rhs); requires Same<decltype(lhs = std::forward<RHS>(rhs)), LHS>; };
Let:
  • lhs be an lvalue that refers to an object lcopy such that decltype((lhs)) is LHS,
  • rhs be an expression such that decltype((rhs)) is RHS, and
  • rcopy be a distinct object that is equal to rhs.
Assignable<LHS, RHS> is satisfied only if
  • addressof(lhs = rhs) == addressof(lcopy).
  • After evaluating lhs = rhs:
    • lhs is equal to rcopy, unless rhs is a non-const xvalue that refers to lcopy.
    • If rhs is a non-const xvalue, the resulting state of the object to which it refers is valid but unspecified ([lib.types.movedfrom]).
    • Otherwise, if rhs is a glvalue, the object to which it refers is not modified.
[Note
:
Assignment need not be a total function ([structure.requirements]); in particular, if assignment to an object x can result in a modification of some other object y, then x = y is likely not in the domain of =.
end note
]

17.4.9 Concept Swappable [concept.swappable]

template<class T> concept Swappable = is_swappable_v<T>;
Let a1 and a2 denote distinct equal objects of type T, and let b1 and b2 similarly denote distinct equal objects of type T.
Swappable<T> is satisfied only if after evaluating either swap(a1, b1) or swap(b1, a1) in the context described below, a1 is equal to b2 and b1 is equal to a2.
The context in which swap(a1, b1) or swap(b1, a1) is evaluated shall ensure that a binary non-member function named swap is selected via overload resolution ([over.match]) on a candidate set that includes:
template<class T, class U> concept SwappableWith = is_swappable_with_v<T, T> && is_swappable_with_v<U, U> && CommonReference<const remove_reference_t<T>&, const remove_reference_t<U>&> && is_swappable_with_v<T, U> && is_swappable_with_v<U, T>;
Let:
  • t1 and t2 denote distinct equal objects of type remove_­cvref_­t<T>,
  • be an expression that denotes t1 such that decltype(()) is T,
  • u1 and u2 similarly denote distinct equal objects of type remove_­cvref_­t<U>,
  • be an expression that denotes u1 such that decltype(()) is U, and
  • C be
        common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>
      
SwappableWith<T, U> is satisfied only if after evaluating either swap(, ) or swap(, ) in the context described above, C(t1) is equal to C(u2) and C(u1) is equal to C(t2).
The context in which swap(, ) or swap(, ) is evaluated shall ensure that a binary non-member function named swap is selected via overload resolution ([over.match]) on a candidate set that includes:
[Example
:
User code can ensure that the evaluation of swap calls is performed in an appropriate context under the various conditions as follows:
#include <cassert>
#include <concepts>
#include <utility>

template<class T, std::SwappableWith<T> U>
void value_swap(T&& t, U&& u) {
  using std::swap;
  swap(std::forward<T>(t), std::forward<U>(u)); // OK: uses “swappable with” conditions
                                                // for rvalues and lvalues
}

template<std::Swappable T>
void lv_swap(T& t1, T& t2) {
  using std::swap;
  swap(t1, t2);                                 // OK: uses swappable conditions for
}                                               // lvalues of type T

namespace N {
  struct A { int m; };
  struct Proxy { A* a; };
  Proxy proxy(A& a) { return Proxy{ &a }; }

  void swap(A& x, Proxy p) {
    std::swap(x.m, p.a->m);                     // OK: uses context equivalent to swappable
                                                // conditions for fundamental types
  }
  void swap(Proxy p, A& x) { swap(x, p); }      // satisfy symmetry constraint
}

int main() {
  int i = 1, j = 2;
  lv_swap(i, j);
  assert(i == 2 && j == 1);

  N::A a1 = { 5 }, a2 = { -5 };
  value_swap(a1, proxy(a2));
  assert(a1.m == -5 && a2.m == 5);
}
end example
]

17.4.10 Concept Destructible [concept.destructible]

The Destructible concept specifies properties of all types, instances of which can be destroyed at the end of their lifetime, or reference types.
template<class T> concept Destructible = is_nothrow_destructible_v<T>;
[Note
:
Unlike the Cpp17Destructible requirements (Table 29), this concept forbids destructors that are potentially throwing, even if a particular invocation of the destructor does not actually throw.
end note
]

17.4.11 Concept Constructible [concept.constructible]

The Constructible concept constrains the initialization of a variable of a given type with a particular set of argument types.
template<class T, class... Args> concept Constructible = Destructible<T> && is_constructible_v<T, Args...>;

17.4.12 Concept DefaultConstructible [concept.defaultconstructible]

template<class T> concept DefaultConstructible = Constructible<T>;

17.4.13 Concept MoveConstructible [concept.moveconstructible]

template<class T> concept MoveConstructible = Constructible<T, T> && ConvertibleTo<T, T>;
If T is an object type, then let rv be an rvalue of type T and u2 a distinct object of type T equal to rv.
MoveConstructible<T> is satisfied only if
  • After the definition T u = rv;, u is equal to u2.
  • T(rv) is equal to u2.
  • If T is not const, rv's resulting state is valid but unspecified ([lib.types.movedfrom]); otherwise, it is unchanged.

17.4.14 Concept CopyConstructible [concept.copyconstructible]

template<class T> concept CopyConstructible = MoveConstructible<T> && Constructible<T, T&> && ConvertibleTo<T&, T> && Constructible<T, const T&> && ConvertibleTo<const T&, T> && Constructible<T, const T> && ConvertibleTo<const T, T>;
If T is an object type, then let v be an lvalue of type (possibly const) T or an rvalue of type const T.
CopyConstructible<T> is satisfied only if
  • After the definition T u = v;, u is equal to v.
  • T(v) is equal to v.

17.5 Comparison concepts [concepts.compare]

17.5.1 General [concepts.compare.general]

This subclause describes concepts that establish relationships and orderings on values of possibly differing object types.

17.5.2 Concept Boolean [concept.boolean]

The Boolean concept specifies the requirements on a type that is usable in Boolean contexts.
template<class B> concept Boolean = Movable<remove_cvref_t<B>> && // (see [concepts.object]) requires(const remove_reference_t<B>& b1, const remove_reference_t<B>& b2, const bool a) { requires ConvertibleTo<const remove_reference_t<B>&, bool>; !b1; requires ConvertibleTo<decltype(!b1), bool>; b1 && a; requires Same<decltype(b1 && a), bool>; b1 || a; requires Same<decltype(b1 || a), bool>; b1 && b2; requires Same<decltype(b1 && b2), bool>; a && b2; requires Same<decltype( a && b2), bool>; b1 || b2; requires Same<decltype(b1 || b2), bool>; a || b2; requires Same<decltype( a || b2), bool>; b1 == b2; requires ConvertibleTo<decltype(b1 == b2), bool>; b1 == a; requires ConvertibleTo<decltype(b1 == a), bool>; a == b2; requires ConvertibleTo<decltype( a == b2), bool>; b1 != b2; requires ConvertibleTo<decltype(b1 != b2), bool>; b1 != a; requires ConvertibleTo<decltype(b1 != a), bool>; a != b2; requires ConvertibleTo<decltype( a != b2), bool>; };
Let b1 and b2 be lvalues of type const remove_­reference_­t<B>.
Boolean<B> is satisfied only if
  • bool(b1) == !bool(!b1).
  • (b1 && b2), (b1 && bool(b2)), and (bool(b1) && b2) are all equal to (bool(b1) && bool(b2)), and have the same short-circuit evaluation.
  • (b1 || b2), (b1 || bool(b2)), and (bool(b1) || b2) are all equal to (bool(b1) || bool(b2)), and have the same short-circuit evaluation.
  • bool(b1 == b2), bool(b1 == bool(b2)), and bool(bool(b1) == b2) are all equal to (bool(b1) == bool(b2)).
  • bool(b1 != b2), bool(b1 != bool(b2)), and bool(bool(b1) != b2) are all equal to (bool(b1) != bool(b2)).
[Example
:
The types bool, true_­type ([meta.type.synop]), and bitset<N>::reference ([template.bitset]) are Boolean types.
Pointers, smart pointers, and types with only explicit conversions to bool are not Boolean types.
end example
]

17.5.3 Concept EqualityComparable [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; requires Boolean<decltype(t == u)>; t != u; requires Boolean<decltype(t != u)>; u == t; requires Boolean<decltype(u == t)>; u != t; requires Boolean<decltype(u != t)>; };
Let t and u be lvalues of types const remove_­reference_­t<T> and const remove_­reference_­t<U> respectively.
weakly-equality-comparable-with<T, U> is satisfied 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).
template<class T> concept EqualityComparable = weakly-equality-comparable-with<T, T>;
Let a and b be objects of type T.
EqualityComparable<T> is satisfied only if bool(a == b) is true when a is equal to b ([concepts.equality]), and false otherwise.
[Note
:
The requirement that the expression a == b is equality-preserving implies that == is transitive and symmetric.
end note
]
template<class T, class U> concept EqualityComparableWith = EqualityComparable<T> && EqualityComparable<U> && CommonReference<const remove_reference_t<T>&, const remove_reference_t<U>&> && EqualityComparable< common_reference_t< const remove_reference_t<T>&, const remove_reference_t<U>&>> && weakly-equality-comparable-with<T, U>;
Let t be an lvalue of type const remove_­reference_­t<T>, u be an lvalue of type const remove_­reference_­t<U>, and C be:
common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>
EqualityComparableWith<T, U> is satisfied only if bool(t == u) == bool(C(t) == C(u)).

17.5.4 Concept StrictTotallyOrdered [concept.stricttotallyordered]

template<class T> concept StrictTotallyOrdered = EqualityComparable<T> && requires(const remove_reference_t<T>& a, const remove_reference_t<T>& b) { a < b; requires Boolean<decltype(a < b)>; a > b; requires Boolean<decltype(a > b)>; a <= b; requires Boolean<decltype(a <= b)>; a >= b; requires Boolean<decltype(a >= b)>; };
Let a, b, and c be lvalues of type const remove_­reference_­t<T>.
StrictTotallyOrdered<T> is satisfied 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(b < a).
  • bool(a >= b) == !bool(a < b).
template<class T, class U> concept StrictTotallyOrderedWith = StrictTotallyOrdered<T> && StrictTotallyOrdered<U> && CommonReference<const remove_reference_t<T>&, const remove_reference_t<U>&> && StrictTotallyOrdered< common_reference_t< const remove_reference_t<T>&, const remove_reference_t<U>&>> && EqualityComparableWith<T, U> && requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) { t < u; requires Boolean<decltype(t < u)>; t > u; requires Boolean<decltype(t > u)>; t <= u; requires Boolean<decltype(t <= u)>; t >= u; requires Boolean<decltype(t >= u)>; u < t; requires Boolean<decltype(u < t)>; u > t; requires Boolean<decltype(u > t)>; u <= t; requires Boolean<decltype(u <= t)>; u >= t; requires Boolean<decltype(u >= t)>; };
Let t be an lvalue of type const remove_­reference_­t<T>, u be an lvalue of type const remove_­reference_­t<U>, and C be:
common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>
StrictTotallyOrderedWith<T, U> is satisfied only if
  • bool(t < u) == bool(C(t) < C(u)).
  • bool(t > u) == bool(C(t) > C(u)).
  • bool(t <= u) == bool(C(t) <= C(u)).
  • bool(t >= u) == bool(C(t) >= C(u)).
  • bool(u < t) == bool(C(u) < C(t)).
  • bool(u > t) == bool(C(u) > C(t)).
  • bool(u <= t) == bool(C(u) <= C(t)).
  • bool(u >= t) == bool(C(u) >= C(t)).

17.6 Object concepts [concepts.object]

This subclause describes concepts that specify the basis of the value-oriented programming style on which the library is based.
template<class T> concept Movable = is_object_v<T> && MoveConstructible<T> && Assignable<T&, T> && Swappable<T>; template<class T> concept Copyable = CopyConstructible<T> && Movable<T> && Assignable<T&, const T&>; template<class T> concept Semiregular = Copyable<T> && DefaultConstructible<T>; template<class T> concept Regular = Semiregular<T> && EqualityComparable<T>;
[Note
:
The Semiregular concept is satisfied by types that behave similarly to built-in types like int, except that they might not be comparable with ==.
end note
]
[Note
:
The Regular concept is satisfied by types that behave similarly to built-in types like int and that are comparable with ==.
end note
]

17.7 Callable concepts [concepts.callable]

17.7.1 General [concepts.callable.general]

The concepts in this subclause describe the requirements on function objects ([function.objects]) and their arguments.

17.7.2 Concept Invocable [concept.invocable]

The Invocable concept specifies a relationship between a callable type ([func.def]) F and a set of argument types Args... which can be evaluated by the library function invoke ([func.invoke]).
template<class F, class... Args> concept Invocable = requires(F&& f, Args&&... args) { invoke(std::forward<F>(f), std::forward<Args>(args)...); // not required to be equality-preserving };
[Example
:
A function that generates random numbers can satisfy Invocable, since the invoke function call expression is not required to be equality-preserving ([concepts.equality]).
end example
]

17.7.3 Concept RegularInvocable [concept.regularinvocable]

template<class F, class... Args> concept RegularInvocable = Invocable<F, Args...>;
The invoke function call expression shall be equality-preserving and shall not modify the function object or the arguments ([concepts.equality]).
[Note
:
This requirement supersedes the annotation in the definition of Invocable.
end note
]
[Example
:
A random number generator does not satisfy RegularInvocable.
end example
]
[Note
:
The distinction between Invocable and RegularInvocable is purely semantic.
end note
]

17.7.4 Concept Predicate [concept.predicate]

template<class F, class... Args> concept Predicate = RegularInvocable<F, Args...> && Boolean<invoke_result_t<F, Args...>>;

17.7.5 Concept Relation [concept.relation]

template<class R, class T, class U> concept Relation = Predicate<R, T, T> && Predicate<R, U, U> && CommonReference<const remove_reference_t<T>&, const remove_reference_t<U>&> && Predicate<R, common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>, common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>> && Predicate<R, T, U> && Predicate<R, U, T>;
Let
  • r be an expression such that decltype((r)) is R,
  • t be an expression such that decltype((t)) is T,
  • u be an expression such that decltype((u)) is U, and
  • C be
      common_reference_t<const remove_reference_t<T>&,
                         const remove_reference_t<U>&>
      
Relation<R, T, U> is satisfied only if
  • bool(r(t, u)) == bool(r(C(t), C(u))).
  • bool(r(u, t)) == bool(r(C(u), C(t))).

17.7.6 Concept StrictWeakOrder [concept.strictweakorder]

template<class R, class T, class U> concept StrictWeakOrder = Relation<R, T, U>;
A Relation satisfies StrictWeakOrder only if it imposes a strict weak ordering on its arguments.
The term strict refers to the requirement of an irreflexive relation (!comp(x, x) for all x), and the term weak to requirements that are not as strong as those for a total ordering, but stronger than those for a partial ordering.
If we define equiv(a, b) as !comp(a, b) && !comp(b, a), then the requirements are that comp and equiv both be transitive relations:
  • comp(a, b) && comp(b, c) implies comp(a, c)
  • equiv(a, b) && equiv(b, c) implies equiv(a, c)
[Note
:
Under these conditions, it can be shown that
  • equiv is an equivalence relation,
  • comp induces a well-defined relation on the equivalence classes determined by equiv, and
  • the induced relation is a strict total ordering.
end note
]