8 General utilities library [utilities]

8.4 Metaprogramming and type traits [meta]

8.4.1 Header <experimental/ranges/type_traits> synopsis [meta.type.synop]

namespace std { namespace experimental { namespace ranges { inline namespace v1 {
  // [meta.unary.prop], type properties:
  template <class T, class U> struct is_swappable_with;
  template <class T> struct is_swappable;

  template <class T, class U> struct is_nothrow_swappable_with;
  template <class T> struct is_nothrow_swappable;

  template <class T, class U> constexpr bool is_swappable_with_v
    = is_swappable_with<T, U>::value;
  template <class T> constexpr bool is_swappable_v
    = is_swappable<T>::value;

  template <class T, class U> constexpr bool is_nothrow_swappable_with_v
    = is_nothrow_swappable_with<T, U>::value;
  template <class T> constexpr bool is_nothrow_swappable_v
    = is_nothrow_swappable<T>::value;

  // [meta.trans.other], other transformations:
  template <class... T> struct common_type;
  template <class T, class U, template <class> class TQual, template <class> class UQual>
    struct basic_common_reference { };
  template <class... T> struct common_reference;

  template <class... T>
    using common_type_t = typename common_type<T...>::type;
  template <class... T>
    using common_reference_t = typename common_reference<T...>::type;
}}}}

8.4.2 Type properties [meta.unary.prop]

These templates provide access to some of the more important properties of types.

It is unspecified whether the library defines any full or partial specializations of any of these templates.

For all of the class templates X declared in this subclause, instantiating that template with a template argument that is a class template specialization may result in the implicit instantiation of the template argument if and only if the semantics of X require that the argument must be a complete type.

For the purpose of defining the templates in this subclause, a function call expression declval<T>() for any type T is considered to be a trivial ( ISO/IEC 14882:2014 §[basic.types], ISO/IEC 14882:2014 §[special]) function call that is not an odr-use ( ISO/IEC 14882:2014 §[basic.def.odr]) of declval in the context of the corresponding definition notwithstanding the restrictions of ( ISO/IEC 14882:2014 §[declval]).

Table 5 — Additional type property predicates
TemplateConditionPrecondition
template <class T, class U>
struct is_swappable_with;
The expressions ranges::swap(declval<T>(), declval<U>()) and ranges::swap(declval<U>(), declval<T>()) are each well-formed when treated as an unevaluated operand (Clause ISO/IEC 14882:2014 §[expr]). Access checking is performed as if in a context unrelated to T and U. Only the validity of the immediate context of the swap expressions is considered. [ Note: The compilation of the expressions can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the “immediate context” and can result in the program being ill-formed.  — end note ] T and U shall be complete types, (possibly cv-qualified) void, or arrays of unknown bound.
template <class T>
struct is_swappable;
For a referenceable type T, the same result as is_swappable_with_v<T&, T&>, otherwise false. T shall be a complete type, (possibly cv-qualified) void, or an array of unknown bound.
template <class T, class U>
struct is_nothrow_swappable_with;
is_swappable_with_v<T, U> is true and each swap expression of the definition of is_swappable_with<T, U> is known not to throw any exceptions ( ISO/IEC 14882:2014 §[expr.unary.noexcept]). T and U shall be complete types, (possibly cv-qualified) void, or arrays of unknown bound.
template <class T>
struct is_nothrow_swappable;
For a referenceable type T, the same result as is_nothrow_swappable_with_v<T&, T&>, otherwise false. T shall be a complete type, (possibly cv-qualified) void, or an array of unknown bound.

8.4.3 Other transformations [meta.trans.other]

Table 6 — Other transformations
TemplateComments
template <class... T>
struct common_type;
The member typedef type shall be defined or omitted as specified below. If it is omitted, there shall be no member type. Each type in the parameter pack T shall be complete or (possibly cv) void. A program may specialize this trait if at least one template parameter in the specialization depends on a user-defined type and sizeof...(T) == 2. [ Note: Such specializations are needed when only explicit conversions are desired among the template arguments.  — end note ]
template <class T, class U,
template <class> class TQual,
template <class> class UQual>
struct basic_common_reference;
The primary template shall have no member typedef type. A program may specialize this trait if at least one template parameter in the specialization depends on a user-defined type. In such a specialization, a member typedef type may be defined or omitted. If it is omitted, there shall be no member type. [ Note: Such specializations may be used to influence the result of common_reference. — end note ]
template <class... T>
struct common_reference;
The member typedef type shall be defined or omitted as specified below. If it is omitted, there shall be no member type. Each type in the parameter pack T shall be complete or (possibly cv) void.

Let CREF(A) be add_lvalue_reference_t<const remove_reference_t<A>>. Let UNCVREF(A) be remove_cv_t<remove_reference_t<A>>. Let XREF(A) denote a unary template T such that T<UNCVREF(A)> denotes the same type as A. Let COPYCV(FROM, TO) be an alias for type TO with the addition of FROM's top-level cv-qualifiers. [ Example: COPYCV(const int, volatile short) is an alias for const volatile short.  — end example ] Let RREF_RES(Z) be remove_reference_t<Z>&& if Z is a reference type or Z otherwise. Let COND_RES(X, Y) be decltype(declval<bool>() ? declval<X(&)()>()() : declval<Y(&)()>()()). Given types A and B, let X be remove_reference_t<A>, let Y be remove_reference_t<B>, and let COMMON_REF(A, B) be:

  • If A and B are both lvalue reference types, COMMON_REF(A, B) is COND_RES(COPYCV(X, Y) &, COPYCV(Y, X) &).

  • Otherwise, let C be RREF_RES(COMMON_REF(X&, Y&)). If A and B are both rvalue reference types, and C is well-formed, and is_convertible<A, C>::value and is_convertible<B, C>::value are true, then COMMON_REF(A, B) is C.

  • Otherwise, let D be COMMON_REF(const X&, Y&). If A is an rvalue reference and B is an lvalue reference and D is well-formed and is_convertible<A, D>::value is true, then COMMON_REF(A, B) is D.

  • Otherwise, if A is an lvalue reference and B is an rvalue reference, then COMMON_REF(A, B) is COMMON_REF(B, A).

  • Otherwise, COMMON_REF(A, B) is decay_t<COND_RES(CREF(A), CREF(B))>.

If any of the types computed above are ill-formed, then COMMON_REF(A, B) is ill-formed.

Note A: For the common_type trait applied to a parameter pack T of types, the member type shall be either defined or not present as follows:

  • If sizeof...(T) is zero, there shall be no member type.

  • Otherwise, if sizeof...(T) is one, let T1 denote the sole type in the pack T. The member typedef type shall denote the same type as decay_t<T1>.

  • Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in the pack T, and let D1 and D2 be decay_t<T1> and decay_t<T2> respectively. Then

    • If D1 and T1 denote the same type and D2 and T2 denote the same type, then

      • If std::common_type_t<T1, T2> is well-formed, then the member typedef type denotes std::common_type_t<T1, T2>.

      • If COMMON_REF(T1, T2) is well-formed, then the member typedef type denotes that type.

      • Otherwise, there shall be no member type.

    • Otherwise, if common_type_t<D1, D2> is well-formed, then the member typedef type denotes that type.

    • Otherwise, there shall be no member type.

  • Otherwise, if sizeof...(T) is greater than two, let T1, T2, and Rest, respectively, denote the first, second, and (pack of) remaining types comprising T. Let C be the type common_type_t<T1, T2>. Then:

    • If there is such a type C, the member typedef type shall denote the same type, if any, as common_type_t<C, Rest...>.

    • Otherwise, there shall be no member type.

Note B: Notwithstanding the provisions of ISO/IEC 14882:2014 §[meta.type.synop], and pursuant to ISO/IEC 14882:2014 §[namespace.std], a program may specialize common_type<T1, T2> for types T1 and T2 such that is_same<T1, decay_t<T1>>::value and is_same<T2, decay_t<T2>>::value are each true. [ Note: Such specializations are needed when only explicit conversions are desired between the template arguments.  — end note ] Such a specialization need not have a member named type, but if it does, that member shall be a typedef-name for an accessible and unambiguous cv-unqualified non-reference type C to which each of the types T1 and T2 is explicitly convertible. Moreover, common_type_t<T1, T2> shall denote the same type, if any, as does common_type_t<T2, T1>. No diagnostic is required for a violation of this Note's rules.

For the common_reference trait applied to a parameter pack T of types, the member type shall be either defined or not present as follows:

  • If sizeof...(T) is zero, there shall be no member type.

  • Otherwise, if sizeof...(T) is one, let T1 denote the sole type in the pack T. The member typedef type shall denote the same type as T1.

  • Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in the pack T. Then

    • If T1 and T2 are reference types and COMMON_REF(T1, T2) is well-formed and denotes a reference type then the member typedef type denotes that type.

    • Otherwise, if basic_common_reference<UNCVREF(T1), UNCVREF(T2), XREF(T1), XREF(T2)>::type is well-formed, then the member typedef type denotes that type.

    • Otherwise, if COND_RES(T1, T2) is well-formed, then the member typedef type denotes that type.

    • Otherwise, if common_type_t<T1, T2> is well-formed, then the member typedef type denotes that type.

    • Otherwise, there shall be no member type.

  • Otherwise, if sizeof...(T) is greater than two, let T1, T2, and Rest, respectively, denote the first, second, and (pack of) remaining types comprising T. Let C be the type common_reference_t<T1, T2>. Then:

    • If there is such a type C, the member typedef type shall denote the same type, if any, as common_reference_t<C, Rest...>.

    • Otherwise, there shall be no member type.

Notwithstanding the provisions of ISO/IEC 14882:2014 §[meta.type.synop], and pursuant to ISO/IEC 14882:2014 §[namespace.std], a program may specialize basic_common_reference<T, U, TQual, UQual> for types T and U such that is_same<T, decay_t<T>>::value and is_same<U, decay_t<U>>::value are each true. [ Note: Such specializations are needed when only explicit conversions are desired between the template arguments.  — end note ] Such a specialization need not have a member named type, but if it does, that member shall be a typedef-name for an accessible and unambiguous type C to which each of the types TQual<T> and UQual<U> is convertible. Moreover, basic_common_reference<T, U, TQual, UQual>::type shall denote the same type, if any, as does basic_common_reference<U, T, UQual, TQual>::type. A program may not specialize basic_common_reference on the third or fourth parameters, TQual or UQual. No diagnostic is required for a violation of these rules.