7 Concepts library [concepts.lib]

7.1 General [concepts.lib.general]

This Clause describes library components that C++ programs may use to perform compile-time validation of template parameters 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 core language concepts, comparison concepts, object concepts, and function concepts as summarized in Table [tab:concepts.lib.summary].

Table 3 — Fundamental concepts library summary
Subclause Header(s)
[concepts.lib.corelang] Core language concepts <experimental/ranges/concepts>
[concepts.lib.compare] Comparison concepts
[concepts.lib.object] Object concepts
[concepts.lib.callable] Callable concepts

7.1.1 Equality Preservation [concepts.lib.general.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 must 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 specification to be equality preserving are further required to be stable: two evaluations of such an expression with the same input objects must 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 must 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 must 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 bool C =
  requires(T a, T b, const T c, const T d) {
    c == d;           // #1
    a = std::move(b); // #2
    a = c;            // #3
  };

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

a == d;       a == b;             a == move(b);       a == d;
c == a;       c == move(a);       c == move(d);
move(a) == d; move(a) == b;       move(a) == move(b); move(a) == move(d);
move(c) == b; move(c) == move(b); move(c) == d;       move(c) == move(d);

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 = 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 or not an implementation diagnoses as ill-formed a program which requires C<T>.  — end example ]

7.2 Header <experimental/ranges/concepts> synopsis [concepts.lib.synopsis]

namespace std { namespace experimental { namespace ranges { inline namespace v1 {
  // [concepts.lib.corelang], core language concepts:
  // [concepts.lib.corelang.same], Same:
  template <class T, class U>
  concept bool Same = see below;

  // [concepts.lib.corelang.derived], DerivedFrom:
  template <class T, class U>
  concept bool DerivedFrom = see below;

  // [concepts.lib.corelang.convertibleto], ConvertibleTo:
  template <class T, class U>
  concept bool ConvertibleTo = see below;

  // [concepts.lib.corelang.commonref], CommonReference:
  template <class T, class U>
  concept bool CommonReference = see below;

  // [concepts.lib.corelang.common], Common:
  template <class T, class U>
  concept bool Common = see below;

  // [concepts.lib.corelang.integral], Integral:
  template <class T>
  concept bool Integral = see below;

  // [concepts.lib.corelang.signedintegral], SignedIntegral:
  template <class T>
  concept bool SignedIntegral = see below;

  // [concepts.lib.corelang.unsignedintegral], UnsignedIntegral:
  template <class T>
  concept bool UnsignedIntegral = see below;

  // [concepts.lib.corelang.assignable], Assignable:
  template <class T, class U>
  concept bool Assignable = see below;

  // [concepts.lib.corelang.swappable], Swappable:
  template <class T>
  concept bool Swappable = see below;

  template <class T, class U>
  concept bool SwappableWith = see below;

  // [concepts.lib.corelang.destructible], Destructible:
  template <class T>
  concept bool Destructible = see below;

  // [concepts.lib.corelang.constructible], Constructible:
  template <class T, class... Args>
  concept bool Constructible = see below;

  // [concepts.lib.corelang.defaultconstructible], DefaultConstructible:
  template <class T>
  concept bool DefaultConstructible = see below;

  // [concepts.lib.corelang.moveconstructible], MoveConstructible:
  template <class T>
  concept bool MoveConstructible = see below;

  // [concepts.lib.corelang.copyconstructible], CopyConstructible:
  template <class T>
  concept bool CopyConstructible = see below;

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

  // [concepts.lib.compare.equalitycomparable], EqualityComparable:
  template <class T, class U>
  concept bool WeaklyEqualityComparableWith = see below;

  template <class T>
  concept bool EqualityComparable = see below;

  template <class T, class U>
  concept bool EqualityComparableWith = see below;

  // [concepts.lib.compare.stricttotallyordered], StrictTotallyOrdered:
  template <class T>
  concept bool StrictTotallyOrdered = see below;

  template <class T, class U>
  concept bool StrictTotallyOrderedWith = see below;

  // [concepts.lib.object], object concepts:
  // [concepts.lib.object.movable], Movable:
  template <class T>
  concept bool Movable = see below;

  // [concepts.lib.object.copyable], Copyable:
  template <class T>
  concept bool Copyable = see below;

  // [concepts.lib.object.semiregular], Semiregular:
  template <class T>
  concept bool Semiregular = see below;

  // [concepts.lib.object.regular], Regular:
  template <class T>
  concept bool Regular = see below;

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

  // [concepts.lib.callable.regularinvocable], RegularInvocable:
  template <class F, class... Args>
  concept bool RegularInvocable = see below;

  // [concepts.lib.callable.predicate], Predicate:
  template <class F, class... Args>
  concept bool Predicate = see below;

  // [concepts.lib.callable.relation], Relation:
  template <class R, class T, class U>
  concept bool Relation = see below;

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

7.3 Core language concepts [concepts.lib.corelang]

7.3.1 General [concepts.lib.corelang.general]

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

7.3.2 Concept Same [concepts.lib.corelang.same]

template <class T, class U> concept bool Same = is_same<T, U>::value; // see below

There need not be any subsumption relationship between Same<T, U> and is_same<T, U>::value.

Remarks: For the purposes of constraint checking, Same<T, U> implies Same<U, T>.

7.3.3 Concept DerivedFrom [concepts.lib.corelang.derived]

template <class T, class U> concept bool DerivedFrom = is_base_of<U, T>::value && is_convertible<remove_cv_t<T>*, remove_cv_t<U>*>::value; // see below

There need not be any subsumption relationship between DerivedFrom<T, U> and either is_base_of<U, T>::value or is_convertible<remove_cv_t<T>*, remove_cv_t<U>*>::value.

Note: DerivedFrom<T, U> is satisfied if and only if T is publicly and unambiguously derived from U, or T and U are the same class type ignoring cv-qualifiers.  — end note ]

7.3.4 Concept ConvertibleTo [concepts.lib.corelang.convertibleto]

template <class T, class U> concept bool ConvertibleTo = is_convertible<From, To>::value && // see below 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 ( ISO/IEC 14882:2014 §[lib.types.movedfrom]).

    • Otherwise, the object referred to by f() is not modified by either above expression.

There need not be any subsumption relationship between ConvertibleTo<From, To> and is_convertible<From, To>::value.

7.3.5 Concept CommonReference [concepts.lib.corelang.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. C need not be unique. — end note ]

template <class T, class U> concept bool 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:

Note: Users can customize the behavior of CommonReference by specializing the basic_common_reference class template ([meta.trans.other]). — end note ]

7.3.6 Concept Common [concepts.lib.corelang.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 may not be unique. — end note ]

template <class T, class U> concept bool 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.unary.prop]). — end note ]

7.3.7 Concept Integral [concepts.lib.corelang.integral]

template <class T> concept bool Integral = is_integral<T>::value; // see below

There need not be any subsumption relationship between Integral<T> and is_integral<T>::value.

7.3.8 Concept SignedIntegral [concepts.lib.corelang.signedintegral]

template <class T> concept bool SignedIntegral = Integral<T> && is_signed<T>::value; // see below

There need not be any subsumption relationship between SignedIntegral<T> and is_signed<T>::value.

Note: SignedIntegral<T> may be satisfied even for types that are not signed integral types ( ISO/IEC 14882:2014 §[basic.fundamental]); for example, char.  — end note ]

7.3.9 Concept UnsignedIntegral [concepts.lib.corelang.unsignedintegral]

template <class T> concept bool UnsignedIntegral = Integral<T> && !SignedIntegral<T>;

Note: UnsignedIntegral<T> may be satisfied even for types that are not unsigned integral types ( ISO/IEC 14882:2014 §[basic.fundamental]); for example, char.  — end note ]

7.3.10 Concept Assignable [concepts.lib.corelang.assignable]

template <class T, class U> concept bool Assignable = is_lvalue_reference<T>::value && // see below CommonReference< const remove_reference_t<T>&, const remove_reference_t<U>&> && requires(T t, U&& u) { { t = std::forward<U>(u) } -> Same<T>&&; };

Let t be an lvalue that refers to an object o such that decltype((t)) is T, and u an expression such that decltype((u)) is U. Let u2 be a distinct object that is equal to u. Assignable<T, U> is satisfied only if

  • addressof(t = u) == addressof(o).

  • After evaluating t = u:

    • t is equal to u2, unless u is a non-const xvalue that refers to o.

    • If u is a non-const xvalue, the resulting state of the object to which it refers is valid but unspecified ( ISO/IEC 14882:2014 §[lib.types.movedfrom]).

    • Otherwise, if u is a glvalue, the object to which it refers is not modified.

There need not be any subsumption relationship between Assignable<T, U> and is_lvalue_reference<T>::value.

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 ]

7.3.11 Concept Swappable [concepts.lib.corelang.swappable]

template <class T> concept bool Swappable = requires(T& a, T& b) { ranges::swap(a, b); }; template <class T, class U> concept bool SwappableWith = CommonReference< const remove_reference_t<T>&, const remove_reference_t<U>&> && requires(T&& t, U&& u) { ranges::swap(std::forward<T>(t), std::forward<T>(t)); ranges::swap(std::forward<U>(u), std::forward<U>(u)); ranges::swap(std::forward<T>(t), std::forward<U>(u)); ranges::swap(std::forward<U>(u), std::forward<T>(t)); };

This subclause provides definitions for swappable types and expressions. In these definitions, let t denote an expression of type T, and let u denote an expression of type U.

An object t is swappable with an object u if and only if SwappableWith<T, U> is satisfied. SwappableWith<T, U> is satisfied only if given distinct objects t2 equal to t and u2 equal to u, after evaluating either ranges::swap(t, u) or ranges::swap(u, t), t2 is equal to u and u2 is equal to t.

An rvalue or lvalue t is swappable if and only if t is swappable with any rvalue or lvalue, respectively, of type T.

Example: User code can ensure that the evaluation of swap calls is performed in an appropriate context under the various conditions as follows:

#include <utility>

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

// Requires: lvalues of T shall be swappable.
template <class T>
void lv_swap(T& t1, T& t2) {
  using std::experimental::ranges::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::experimental::ranges::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 ]

7.3.12 Concept Destructible [concepts.lib.corelang.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 bool Destructible = is_nothrow_destructible<T>::value; // see below

There need not be any subsumption relationship between Destructible<T> and is_nothrow_destructible<T>::value.

Note: Unlike the Destructible library concept in the C++ Standard ( ISO/IEC 14882:2014 §[utility.arg.requirements]), this concept forbids destructors that are noexcept(false), even if non-throwing.  — end note ]

7.3.13 Concept Constructible [concepts.lib.corelang.constructible]

The Constructible concept constrains the initialization of a variable of a type with a given set of argument types.

template <class T, class... Args> concept bool Constructible = Destructible<T> && is_constructible<T, Args...>::value; // see below

There need not be any subsumption relationship between Constructible<T, Args...> and is_constructible<T, Args...>::value.

7.3.14 Concept DefaultConstructible [concepts.lib.corelang.defaultconstructible]

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

7.3.15 Concept MoveConstructible [concepts.lib.corelang.moveconstructible]

template <class T> concept bool 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 ( ISO/IEC 14882:2014 §[lib.types.movedfrom]); otherwise, it is unchanged.

7.3.16 Concept CopyConstructible [concepts.lib.corelang.copyconstructible]

template <class T> concept bool 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.

7.4 Comparison concepts [concepts.lib.compare]

7.4.1 General [concepts.lib.compare.general]

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

7.4.2 Concept Boolean [concepts.lib.compare.boolean]

The Boolean concept specifies the requirements on a type that is usable in Boolean contexts.

template <class B> concept bool Boolean = Movable<decay_t<B>> && // (see [concepts.lib.object.movable]) requires(const remove_reference_t<B>& b1, const remove_reference_t<B>& b2, const bool a) { { b1 } -> ConvertibleTo<bool>&&; { !b1 } -> ConvertibleTo<bool>&&; { b1 && a } -> Same<bool>&&; { b1 || a } -> Same<bool>&&; { b1 && b2 } -> Same<bool>&&; { a && b2 } -> Same<bool>&&; { b1 || b2 } -> Same<bool>&&; { a || b2 } -> Same<bool>&&; { b1 == b2 } -> ConvertibleTo<bool>&&; { b1 == a } -> ConvertibleTo<bool>&&; { a == b2 } -> ConvertibleTo<bool>&&; { b1 != b2 } -> ConvertibleTo<bool>&&; { b1 != a } -> ConvertibleTo<bool>&&; { a != b2 } -> ConvertibleTo<bool>&&; };

Given const lvalues b1 and b2 of type remove_reference_t<B>, then 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, std::true_type, and std::bitset<N>::reference are Boolean types. Pointers, smart pointers, and types with explicit conversions to bool are not Boolean types. — end example ]

7.4.3 Concept EqualityComparable [concepts.lib.compare.equalitycomparable]

template <class T, class U> concept bool WeaklyEqualityComparableWith = requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) { { t == u } -> Boolean&&; { t != u } -> Boolean&&; { u == t } -> Boolean&&; { u != t } -> Boolean&&; };

Let t and u be const lvalues of types remove_reference_t<T> and remove_reference_t<U> respectively. WeaklyEqualityComparableWith<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 bool EqualityComparable = WeaklyEqualityComparableWith<T, T>;

Let a and b be objects of type T. EqualityComparable<T> is satisfied only if:

  • bool(a == b) if and only if a is equal to b.

Note: The requirement that the expression a == b is equality preserving implies that == is reflexive, transitive, and symmetric. — end note ]

template <class T, class U> concept bool 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>&>> && WeaklyEqualityComparableWith<T, U>;

Let t be a const lvalue of type remove_reference_t<T>, u be a const lvalue of type 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)).

7.4.4 Concept StrictTotallyOrdered [concepts.lib.compare.stricttotallyordered]

template <class T> concept bool StrictTotallyOrdered = EqualityComparable<T> && requires(const remove_reference_t<T>& a, const remove_reference_t<T>& b) { { a < b } -> Boolean&&; { a > b } -> Boolean&&; { a <= b } -> Boolean&&; { a >= b } -> Boolean&&; };

Let a, b, and c be const lvalues of type 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 bool 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 } -> Boolean&&; { t > u } -> Boolean&&; { t <= u } -> Boolean&&; { t >= u } -> Boolean&&; { u < t } -> Boolean&&; { u > t } -> Boolean&&; { u <= t } -> Boolean&&; { u >= t } -> Boolean&&; };

Let t be a const lvalue of type remove_reference_t<T>, u be a const lvalue of type 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)).

7.5 Object concepts [concepts.lib.object]

This section describes concepts that specify the basis of the value-oriented programming style on which the library is based.

7.5.1 Concept Movable [concepts.lib.object.movable]

template <class T> concept bool Movable = is_object<T>::value && MoveConstructible<T> && Assignable<T&, T> && Swappable<T>;

There need not be any subsumption relationship between Movable<T> and is_object<T>::value.

7.5.2 Concept Copyable [concepts.lib.object.copyable]

template <class T> concept bool Copyable = CopyConstructible<T> && Movable<T> && Assignable<T&, const T&>;

7.5.3 Concept Semiregular [concepts.lib.object.semiregular]

template <class T> concept bool Semiregular = Copyable<T> && DefaultConstructible<T>;

Note: The Semiregular concept is satisfied by types that behave similarly to built-in types like int, except that they may not be comparable with ==. — end note ]

7.5.4 Concept Regular [concepts.lib.object.regular]

template <class T> concept bool Regular = Semiregular<T> && EqualityComparable<T>;

Note: The Regular concept is satisfied by types that behave similarly to built-in types like int and that are comparable with ==. — end note ]

7.6 Callable concepts [concepts.lib.callable]

7.6.1 General [concepts.lib.callable.general]

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

7.6.2 Concept Invocable [concepts.lib.callable.invocable]

The Invocable concept specifies a relationship between a callable type ( ISO/IEC 14882:2014 §[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 bool Invocable = requires(F&& f, Args&&... args) { invoke(std::forward<F>(f), std::forward<Args>(args)...); // not required to be equality preserving };

Note: Since the invoke function call expression is not required to be equality-preserving ([concepts.lib.general.equality]), a function that generates random numbers may satisfy Invocable. — end note ]

7.6.3 Concept RegularInvocable [concepts.lib.callable.regularinvocable]

template <class F, class... Args> concept bool RegularInvocable = Invocable<F, Args...>;

The invoke function call expression shall be equality-preserving and shall not modify the function object or the arguments ([concepts.lib.general.equality]). [ Note: This requirement supersedes the annotation in the definition of Invocable.  — end note ]

Note: A random number generator does not satisfy RegularInvocable. — end note ]

Note: The distinction between Invocable and RegularInvocable is purely semantic. — end note ]

7.6.4 Concept Predicate [concepts.lib.callable.predicate]

template <class F, class... Args> concept bool Predicate = RegularInvocable<F, Args...> && Boolean<result_of_t<F&&(Args&&...)>>;

7.6.5 Concept Relation [concepts.lib.callable.relation]

template <class R, class T, class U> concept bool 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))).

7.6.6 Concept StrictWeakOrder [concepts.lib.callable.strictweakorder]

template <class R, class T, class U> concept bool 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

    • The induced relation is a strict total ordering.  — end note ]