23 General utilities library [utilities]

23.15 Metaprogramming and type traits [meta]

23.15.7 Transformations between types [meta.trans]

23.15.7.6 Other transformations [meta.trans.other]

Table 50 — Other transformations
Template
Comments
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 C++ object type whose size is no greater than Len ([basic.types]).
The member typedef type shall be a trivial type suitable for use as uninitialized storage for any object whose size is at most Len and whose alignment is a divisor of Align.

Requires: Len shall not be zero.
Align shall be 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 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.

Requires: At least one type is provided.
Each type in the parameter pack Types shall be 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 shall equal remove_­extent_­t<U>*.
If is_­function_­v<U> is true, the member typedef type shall equal add_­pointer_­t<U>.
Otherwise the member typedef type equals remove_­cv_­t<U>.
[Note
:
This behavior is similar to the lvalue-to-rvalue, array-to-pointer, and function-to-pointer conversions applied when an lvalue expression 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 shall be defined or omitted as specified in Note A, below.
If it is omitted, there shall be no member type.
Each type in the parameter pack T shall be complete, cv void, or an array of unknown bound.
template<class T>
struct underlying_­type;
The member typedef type names the underlying type of T.

Requires: T shall be a complete 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
:
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
]

Requires: Fn and all types in the parameter pack ArgTypes shall be complete types, cv void, or arrays of unknown bound.
[Note
:
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
]
It is implementation-defined whether any extended alignment is supported.
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.
  • 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>.
    • Otherwise, let C denote the same type, if any, as
      decay_t<decltype(false ? declval<D1>() : declval<D2>())>
      [Note
      :
      This will not apply if there is a specialization common_­type<D1, D2>.
      end note
      ]
    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
:
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.
[Example
:
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
]