7 Concepts library [concepts.lib]

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.