20 General utilities library [utilities]

20.15 Metaprogramming and type traits [meta]

20.15.8 Transformations between types [meta.trans]

20.15.8.1 General [meta.trans.general]

Subclause [meta.trans] contains templates that may be used to transform one type to another following some predefined rule.
Each of the templates in [meta.trans] shall be a Cpp17TransformationTrait ([meta.rqmts]).

20.15.8.2 Const-volatile modifications [meta.trans.cv]

Table 52: Const-volatile modifications [tab:meta.trans.cv]
Template
Comments
template<class T>
struct remove_­const;
The member typedef type names the same type as T except that any top-level const-qualifier has been removed.
[Example 1:
remove_­const_­t<const volatile int> evaluates to volatile int, whereas remove_­const_­t<const int*> evaluates to const int*.
β€” end example]
template<class T>
struct remove_­volatile;
The member typedef type names the same type as T except that any top-level volatile-qualifier has been removed.
[Example 2:
remove_­volatile_­t<const volatile int> evaluates to const int, whereas remove_­volatile_­t<volatile int*> evaluates to volatile int*.
β€” end example]
template<class T>
struct remove_­cv;
The member typedef type shall be the same as T except that any top-level cv-qualifier has been removed.
[Example 3:
remove_­cv_­t<const volatile int> evaluates to int, whereas remove_­cv_­t<const volatile int*> evaluates to const volatile int*.
β€” end example]
template<class T>
struct add_­const;
If T is a reference, function, or top-level const-qualified type, then type names the same type as T, otherwise T const.
template<class T>
struct add_­volatile;
If T is a reference, function, or top-level volatile-qualified type, then type names the same type as T, otherwise T volatile.
template<class T>
struct add_­cv;
The member typedef type names the same type as add_­const_­t<add_­volatile_­t<T>>.

20.15.8.3 Reference modifications [meta.trans.ref]

Table 53: Reference modifications [tab:meta.trans.ref]
Template
Comments
template<class T>
struct remove_­reference;
If T has type β€œreference to T1” then the member typedef type names T1; otherwise, type names T.
template<class T>
struct add_­lvalue_­reference;
If T names a referenceable type then the member typedef type names T&; otherwise, type names T.
[Note 1:
This rule reflects the semantics of reference collapsing ([dcl.ref]).
β€” end note]
template<class T>
struct add_­rvalue_­reference;
If T names a referenceable type then the member typedef type names T&&; otherwise, type names T.
[Note 2:
This rule reflects the semantics of reference collapsing ([dcl.ref]).
For example, when a type T names a type T1&, the type add_­rvalue_­reference_­t<T> is not an rvalue reference.
β€” end note]

20.15.8.4 Sign modifications [meta.trans.sign]

Table 54: Sign modifications [tab:meta.trans.sign]
Template
Comments
template<class T>
struct make_­signed;
If T names a (possibly cv-qualified) signed integer type then the member typedef type names the type T; otherwise, if T names a (possibly cv-qualified) unsigned integer type then type names the corresponding signed integer type, with the same cv-qualifiers as T; otherwise, type names the signed integer type with smallest rank for which sizeof(T) == sizeof(type), with the same cv-qualifiers as T.

Mandates: T is an integral or enumeration type other than cv bool.
template<class T>
struct make_­unsigned;
If T names a (possibly cv-qualified) unsigned integer type then the member typedef type names the type T; otherwise, if T names a (possibly cv-qualified) signed integer type then type names the corresponding unsigned integer type, with the same cv-qualifiers as T; otherwise, type names the unsigned integer type with smallest rank for which sizeof(T) == sizeof(type), with the same cv-qualifiers as T.

Mandates: T is an integral or enumeration type other than cv bool.

20.15.8.5 Array modifications [meta.trans.arr]

Table 55: Array modifications [tab:meta.trans.arr]
Template
Comments
template<class T>
struct remove_­extent;
If T names a type β€œarray of U”, the member typedef type shall be U, otherwise T.
[Note 1:
For multidimensional arrays, only the first array dimension is removed.
For a type β€œarray of const U”, the resulting type is const U.
β€” end note]
template<class T>
struct remove_­all_­extents;
If T is β€œmulti-dimensional array of U”, the resulting member typedef type is U, otherwise T.
[Example 1: // the following assertions hold: assert((is_same_v<remove_extent_t<int>, int>)); assert((is_same_v<remove_extent_t<int[2]>, int>)); assert((is_same_v<remove_extent_t<int[2][3]>, int[3]>)); assert((is_same_v<remove_extent_t<int[][3]>, int[3]>)); β€” end example]
[Example 2: // the following assertions hold: assert((is_same_v<remove_all_extents_t<int>, int>)); assert((is_same_v<remove_all_extents_t<int[2]>, int>)); assert((is_same_v<remove_all_extents_t<int[2][3]>, int>)); assert((is_same_v<remove_all_extents_t<int[][3]>, int>)); β€” end example]

20.15.8.6 Pointer modifications [meta.trans.ptr]

Table 56: Pointer modifications [tab:meta.trans.ptr]
Template
Comments
template<class T>
struct remove_­pointer;
If T has type β€œ(possibly cv-qualified) pointer to T1” then the member typedef type names T1; otherwise, it names T.
template<class T>
struct add_­pointer;
If T names a referenceable type or a cv void type then the member typedef type names the same type as remove_­reference_­t<T>*; otherwise, type names T.

20.15.8.7 Other transformations [meta.trans.other]

Table 57: Other transformations [tab:meta.trans.other]
Template
Comments
template<class T>
struct type_­identity;
The member typedef type names the type T.
template<size_­t Len,
size_­t Align
= default-alignment>
struct aligned_­storage;
The value of default-alignment shall be the most stringent alignment requirement for any object type whose size is no greater than Len ([basic.types]).
The member typedef type shall be a trivial standard-layout type suitable for use as uninitialized storage for any object whose size is at most Len and whose alignment is a divisor of Align.

Mandates: Len is not zero.
Align is equal to alignof(T) for some type T or to default-alignment.
template<size_­t Len,
class... Types>
struct aligned_­union;
The member typedef type shall be a trivial standard-layout type suitable for use as uninitialized storage for any object whose type is listed in Types; its size shall be at least Len.
The static member alignment_­value shall be an integral constant of type size_­t whose value is the strictest alignment of all types listed in Types.

Mandates: At least one type is provided.
Each type in the template parameter pack Types is a complete object type.
template<class T>
struct remove_­cvref;
The member typedef type names the same type as remove_­cv_­t<remove_­reference_­t<T>>.
template<class T>
struct decay;
Let U be remove_­reference_­t<T>.
If is_­array_­v<U> is true, the member typedef type equals remove_­extent_­t<U>*.
If is_­function_­v<U> is true, the member typedef type equals add_­pointer_­t<U>.
Otherwise the member typedef type equals remove_­cv_­t<U>.
[Note 1:
This behavior is similar to the lvalue-to-rvalue ([conv.lval]), array-to-pointer ([conv.array]), and function-to-pointer ([conv.func]) conversions applied when an lvalue is used as an rvalue, but also strips cv-qualifiers from class types in order to more closely model by-value argument passing.
β€” end note]
template<bool B, class T = void> struct enable_­if;
If B is true, the member typedef type shall equal T; otherwise, there shall be no member type.
template<bool B, class T, class F>
struct conditional;
If B is true, the member typedef type shall equal T.
If B is false, the member typedef type shall equal F.
template<class... T> struct common_­type;
Unless this trait is specialized (as specified in Note B, below), the member type is defined or omitted as specified in Note A, below.
If it is omitted, there shall be no member type.
Each type in the template parameter pack T shall be complete, cv void, or an array of unknown bound.
template<class, class, template<class> class, template<class> class> struct basic_­common_­reference;
Unless this trait is specialized (as specified in Note D, below), there shall be no member type.
template<class... T> struct common_­reference;
The member typedef-name type is defined or omitted as specified in Note C, below.
Each type in the parameter pack T shall be complete or cv void.
template<class T>
struct underlying_­type;
If T is an enumeration type, the member typedef type names the underlying type of T ([dcl.enum]); otherwise, there is no member type.

Mandates: T is not an incomplete enumeration type.
template<class Fn,
class... ArgTypes>
struct invoke_­result;
If the expression INVOKE(declval<Fn>(), declval<ArgTypes>()...) is well-formed when treated as an unevaluated operand, the member typedef type names the type decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...)); otherwise, there shall be no member type.
Access checking is performed as if in a context unrelated to Fn and ArgTypes.
Only the validity of the immediate context of the expression is considered.
[Note 2:
The compilation of the expression 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]
Preconditions: Fn and all types in the template parameter pack ArgTypes are complete types, cv void, or arrays of unknown bound.
template<class T> struct unwrap_­reference;
If T is a specialization reference_­wrapper<X> for some type X, the member typedef type of unwrap_­reference<T> is X&, otherwise it is T.
template<class T> unwrap_­ref_­decay;
The member typedef type of unwrap_­ref_­decay<T> denotes the type unwrap_­reference_­t<decay_­t<T>>.
[Note 3:
A typical implementation would define aligned_storage as: template<size_t Len, size_t Alignment> struct aligned_storage { typedef struct { alignas(Alignment) unsigned char __data[Len]; } type; };
β€” end note]
In addition to being available via inclusion of the <type_­traits> header, the templates unwrap_­reference, unwrap_­ref_­decay, unwrap_­reference_­t, and unwrap_­ref_­decay_­t are available when the header <functional> ([functional.syn]) is included.
Let:
  • CREF(A) be add_­lvalue_­reference_­t<const remove_­reference_­t<A>>,
  • XREF(A) denote a unary alias template T such that T<U> denotes the same type as U with the addition of A's cv and reference qualifiers, for a non-reference cv-unqualified type U,
  • COPYCV(FROM, TO) be an alias for type TO with the addition of FROM's top-level cv-qualifiers,
    [Example 1:
    COPYCV(const int, volatile short) is an alias for const volatile short.
    β€” end example]
  • COND-RES(X, Y) be decltype(false ? 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) &) if that type exists and is a reference type.
  • Otherwise, let C be remove_­reference_­t<COMMON-REF(X&, Y&)>&&.
    If A and B are both rvalue reference types, C is well-formed, and is_­convertible_­v<A, C> && is_­convertible_­v<B, C> is 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_­v<A, D> 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 ill-formed.
If any of the types computed above is ill-formed, then COMMON-REF(A, B) is ill-formed.
Note A: For the common_­type trait applied to a template 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.
  • If sizeof...(T) is one, let T0 denote the sole type constituting the pack T.
    The member typedef-name type shall denote the same type, if any, as common_­type_­t<T0, T0>; otherwise there shall be no member type.
  • If sizeof...(T) is two, let the first and second types constituting T be denoted by T1 and T2, respectively, and let D1 and D2 denote the same types as decay_­t<T1> and decay_­t<T2>, respectively.
    • If is_­same_­v<T1, D1> is false or is_­same_­v<T2, D2> is false, let C denote the same type, if any, as common_­type_­t<D1, D2>.
    • [Note 4:
      None of the following will apply if there is a specialization common_­type<D1, D2>.
      β€” end note]
    • Otherwise, if decay_t<decltype(false ? declval<D1>() : declval<D2>())> denotes a valid type, let C denote that type.
    • Otherwise, if COND-RES(CREF(D1), CREF(D2)) denotes a type, let C denote the type decay_­t<COND-RES(CREF(D1), CREF(D2))>.
    In either case, the member typedef-name type shall denote the same type, if any, as C.
    Otherwise, there shall be no member type.
  • If sizeof...(T) is greater than two, let T1, T2, and R, respectively, denote the first, second, and (pack of) remaining types constituting T.
    Let C denote the same type, if any, as common_­type_­t<T1, T2>.
    If there is such a type C, the member typedef-name type shall denote the same type, if any, as common_­type_­t<C, R...>.
    Otherwise, there shall be no member type.
Note B: Notwithstanding the provisions of [meta.type.synop], and pursuant to [namespace.std], a program may specialize common_­type<T1, T2> for types T1 and T2 such that is_­same_­v<T1, decay_­t<T1>> and is_­same_­v<T2, decay_­t<T2>> are each true.
[Note 5:
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.
Note C: 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 T0 denote the sole type in the pack T.
    The member typedef type shall denote the same type as T0.
  • 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, then the member typedef type denotes that type.
    • Otherwise, if basic_­common_­reference<remove_­cvref_­t<T1>, remove_­cvref_­t<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.
Note D: Notwithstanding the provisions of [meta.type.synop], and pursuant to [namespace.std], a program may partially specialize basic_­common_­reference<T, U, TQual, UQual> for types T and U such that is_­same_­v<T, decay_­t<T>> and is_­same_­v<U, decay_­t<U>> are each true.
[Note 6:
Such specializations can be used to influence the result of common_­reference, and 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.
No diagnostic is required for a violation of these rules.
[Example 2:
Given these definitions: using PF1 = bool (&)(); using PF2 = short (*)(long); struct S { operator PF2() const; double operator()(char, int&); void fn(long) const; char data; }; using PMF = void (S::*)(long) const; using PMD = char S::*; the following assertions will hold: static_assert(is_same_v<invoke_result_t<S, int>, short>); static_assert(is_same_v<invoke_result_t<S&, unsigned char, int&>, double>); static_assert(is_same_v<invoke_result_t<PF1>, bool>); static_assert(is_same_v<invoke_result_t<PMF, unique_ptr<S>, int>, void>); static_assert(is_same_v<invoke_result_t<PMD, S>, char&&>); static_assert(is_same_v<invoke_result_t<PMD, const S*>, const char&>);
β€” end example]