Table 59: Other transformations [tab:meta.trans.other]

Template | Comments | |

template<class T> struct type_identity; | ||

template<class T> struct remove_cvref; | ||

template<class T> struct decay; | [ 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; | ||

template<class... T> struct common_type; | ||

Unless this trait is specialized,
there shall be no member type. | ||

If T is an enumeration type, the member typedef type denotes
the underlying type of T ([dcl.enum]);
otherwise, there is no member type. | ||

If the expression INVOKE(declval<Fn>(), declval<ArgTypes>()...) ([func.require])
is well-formed when treated as an unevaluated operand ([expr.context]),
the member typedef type denotes the type
decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...));
otherwise, there shall be no member type.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. | ||

If T is
a specialization reference_wrapper<X> for some type X,
the member typedef type of unwrap_reference<T>
denotes X&,
otherwise type denotes T. | ||

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,*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. - 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. - 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.

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:

- 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, 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))>.

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.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.

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.

Such a specialization need not have a member named type,
but if it does,
the *qualified-id* common_type<T1, T2>::type shall denote
a cv-unqualified non-reference type
to which each of the types T1 and T2 is explicitly convertible.

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:

- Then
- 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.

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.

Such a specialization need not have a member named type, but if it does,
the *qualified-id*
basic_common_reference<T, U, TQual, UQual>::type
shall denote a type
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*: *end 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&>);

β