This section contains the definition of concepts corresponding to language features. These concepts express relationships between types, type classifications, and fundamental type properties.
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>.
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 ]
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.
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:
C(t()) equals C(t()) if and only if t() is an equality preserving expression ([concepts.lib.general.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 ]
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:
C(t()) equals C(t()) if and only if t() is an equality preserving expression ([concepts.lib.general.equality]).
C(u()) equals C(u()) if and only if u() is an equality preserving expression ([concepts.lib.general.equality]).
[ Note: Users can customize the behavior of Common by specializing the common_type class template ([meta.unary.prop]). — end note ]
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.
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 ]
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 ]
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 ]
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 ]
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 ]
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.
template <class T>
concept bool DefaultConstructible = Constructible<T>;
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.
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>;