[meta.trans]

# 21 Metaprogramming library [[meta]](./#meta)

## 21.3 Metaprogramming and type traits [[type.traits]](type.traits#meta.trans)

### 21.3.9 Transformations between types [meta.trans]

#### [21.3.9.1](#general) General [[meta.trans.general]](meta.trans.general)

[1](#general-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L1966)

Subclause [meta.trans] contains templates that may be used to transform one
type to another following some predefined rule[.](#general-1.sentence-1)

[2](#general-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L1970)

Each of the templates in [meta.trans] shall be a[*Cpp17TransformationTrait*](meta.rqmts#:Cpp17TransformationTrait "21.3.2 Requirements [meta.rqmts]") ([[meta.rqmts]](meta.rqmts "21.3.2 Requirements"))[.](#general-2.sentence-1)

#### [21.3.9.2](#cv) Const-volatile modifications [[meta.trans.cv]](meta.trans.cv)

[1](#cv-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L1976)

The templates specified in Table [57](#tab:meta.trans.cv "Table 57: Const-volatile modifications") add or remove cv-qualifications ([[basic.type.qualifier]](basic.type.qualifier "6.9.5 CV-qualifiers"))[.](#cv-1.sentence-1)

Table [57](#tab:meta.trans.cv) — Const-volatile modifications [[tab:meta.trans.cv]](./tab:meta.trans.cv)  

| [ð](#tab:meta.trans.cv-row-1)<br>**Template** | **Comments** |
| --- | --- |
| [ð](#tab:meta.trans.cv-row-2)<br>template<class T>   struct remove_const; | The member typedef type denotes the type formed  by removing any top-level const-qualifier from T[.](#tab:meta.trans.cv-row-2-column-2-sentence-1)<br>[*Example [1](#tab:meta.trans.cv-row-2-column-2-example-1)*:<br>remove_const_t<const volatile int> evaluates  to volatile int, whereas remove_const_t<const int*> evaluates to  const int*[.](#tab:meta.trans.cv-row-2-column-2-sentence-2) â *end example*] |
| [ð](#tab:meta.trans.cv-row-3)<br>template<class T>   struct remove_volatile; | The member typedef type denotes the type formed  by removing any top-level volatile-qualifier from T[.](#tab:meta.trans.cv-row-3-column-2-sentence-1)<br>[*Example [2](#tab:meta.trans.cv-row-3-column-2-example-2)*:<br>remove_volatile_t<const volatile int>  evaluates to const int,  whereas remove_volatile_t<volatile int*> evaluates to volatile int*[.](#tab:meta.trans.cv-row-3-column-2-sentence-2) â *end example*] |
| [ð](#tab:meta.trans.cv-row-4)<br>template<class T>   struct remove_cv; | The member typedef type denotes the type formed  by removing any top-level cv-qualifiers from T[.](#tab:meta.trans.cv-row-4-column-2-sentence-1)<br>[*Example [3](#tab:meta.trans.cv-row-4-column-2-example-3)*:<br>remove_cv_t<const volatile int>  evaluates to int, whereas remove_cv_t<const volatile int*>  evaluates to const volatile int*[.](#tab:meta.trans.cv-row-4-column-2-sentence-2) â *end example*] |
| [ð](#tab:meta.trans.cv-row-5)<br>template<class T>   struct add_const; | The member typedef type denotes const T[.](#tab:meta.trans.cv-row-5-column-2-sentence-1)<br>[*Note [1](#tab:meta.trans.cv-row-5-column-2-note-1)*:<br>const has no effect when T is a reference, function, or top-level const-qualified type[.](#tab:meta.trans.cv-row-5-column-2-sentence-2) â *end note*] |
| [ð](#tab:meta.trans.cv-row-6)<br>template<class T>   struct add_volatile; | The member typedef type denotes volatile T[.](#tab:meta.trans.cv-row-6-column-2-sentence-1)<br>[*Note [2](#tab:meta.trans.cv-row-6-column-2-note-2)*:<br>volatile has no effect when T is a reference, function, or top-level volatile-qualified type[.](#tab:meta.trans.cv-row-6-column-2-sentence-2) â *end note*] |
| [ð](#tab:meta.trans.cv-row-7)<br>template<class T>   struct add_cv; | The member typedef type denotes  add_const_t<add_volatile_t<T>>[.](#tab:meta.trans.cv-row-7-column-2-sentence-1) |

#### [21.3.9.3](#ref) Reference modifications [[meta.trans.ref]](meta.trans.ref)

[1](#ref-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2054)

The templates specified in Table [58](#tab:meta.trans.ref "Table 58: Reference modifications") add or remove references[.](#ref-1.sentence-1)

Table [58](#tab:meta.trans.ref) — Reference modifications [[tab:meta.trans.ref]](./tab:meta.trans.ref)  

| [ð](#tab:meta.trans.ref-row-1)<br>**Template** | **Comments** |
| --- | --- |
| [ð](#tab:meta.trans.ref-row-2)<br>template<class T>   struct remove_reference; | If T has type âreference to T1â then the  member typedef type denotes T1;  otherwise, type denotes T[.](#tab:meta.trans.ref-row-2-column-2-sentence-1) |
| [ð](#tab:meta.trans.ref-row-3)<br>template<class T>   struct add_lvalue_reference; | If T is a referenceable type ([[defns.referenceable]](defns.referenceable "3.45 referenceable type")) then  the member typedef type denotes T&;  otherwise, type denotes T[.](#tab:meta.trans.ref-row-3-column-2-sentence-1)<br>[*Note [1](#tab:meta.trans.ref-row-3-column-2-note-1)*:<br>This rule reflects the semantics of reference collapsing ([[dcl.ref]](dcl.ref "9.3.4.3 References"))[.](#tab:meta.trans.ref-row-3-column-2-sentence-2) â *end note*] |
| [ð](#tab:meta.trans.ref-row-4)<br>template<class T>   struct add_rvalue_reference; | If T is a referenceable type then  the member typedef type denotes T&&;  otherwise, type denotes T[.](#tab:meta.trans.ref-row-4-column-2-sentence-1)<br>[*Note [2](#tab:meta.trans.ref-row-4-column-2-note-2)*:<br>This rule reflects the semantics of reference collapsing ([[dcl.ref]](dcl.ref "9.3.4.3 References"))[.](#tab:meta.trans.ref-row-4-column-2-sentence-2)<br>For example, when a type T is a reference type T1&,  the type add_rvalue_reference_t<T> is not an rvalue reference[.](#tab:meta.trans.ref-row-4-column-2-sentence-3) â *end note*] |

#### [21.3.9.4](#sign) Sign modifications [[meta.trans.sign]](meta.trans.sign)

[1](#sign-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2101)

The templates specified in Table [59](#tab:meta.trans.sign "Table 59: Sign modifications") convert an integer type to its corresponding signed or unsigned type[.](#sign-1.sentence-1)

Table [59](#tab:meta.trans.sign) — Sign modifications [[tab:meta.trans.sign]](./tab:meta.trans.sign)  

| [ð](#tab:meta.trans.sign-row-1)<br>**Template** | **Comments** |
| --- | --- |
| [ð](#tab:meta.trans.sign-row-2)<br>template<class T>   struct make_signed; | If T is a (possibly cv-qualified) signed integer  type ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types")) then the member typedef  type denotes T; otherwise,  if T is a (possibly cv-qualified) unsigned integer  type then type denotes the corresponding  signed integer type, with the same cv-qualifiers as T;  otherwise, type denotes the signed integer type with smallest  rank ([[conv.rank]](conv.rank "6.9.6 Conversion ranks")) for which  sizeof(T) == sizeof(type), with the same  cv-qualifiers as T[.](#tab:meta.trans.sign-row-2-column-2-sentence-1)<br>   *Mandates*: T is an integral or enumeration type  other than cv bool[.](#tab:meta.trans.sign-row-2-column-2-sentence-2) |
| [ð](#tab:meta.trans.sign-row-3)<br>template<class T>   struct make_unsigned; | If T is a (possibly cv-qualified) unsigned integer  type ([[basic.fundamental]](basic.fundamental "6.9.2 Fundamental types")) then the member typedef  type denotes T; otherwise,  if T is a (possibly cv-qualified) signed integer  type then type denotes the corresponding  unsigned integer type, with the same cv-qualifiers as T;  otherwise, type denotes the unsigned integer type with smallest  rank ([[conv.rank]](conv.rank "6.9.6 Conversion ranks")) for which  sizeof(T) == sizeof(type), with the same  cv-qualifiers as T[.](#tab:meta.trans.sign-row-3-column-2-sentence-1)<br>   *Mandates*: T is an integral or enumeration type  other than cv bool[.](#tab:meta.trans.sign-row-3-column-2-sentence-2) |

#### [21.3.9.5](#arr) Array modifications [[meta.trans.arr]](meta.trans.arr)

[1](#arr-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2149)

The templates specified in Table [60](#tab:meta.trans.arr "Table 60: Array modifications") modify array types[.](#arr-1.sentence-1)

Table [60](#tab:meta.trans.arr) — Array modifications [[tab:meta.trans.arr]](./tab:meta.trans.arr)  

| [ð](#tab:meta.trans.arr-row-1)<br>**Template** | **Comments** |
| --- | --- |
| [ð](#tab:meta.trans.arr-row-2)<br>template<class T>   struct remove_extent; | If T is a type âarray of Uâ,  the member typedef type denotes U,  otherwise T[.](#tab:meta.trans.arr-row-2-column-2-sentence-1)<br>[*Note [1](#tab:meta.trans.arr-row-2-column-2-note-1)*:<br>For multidimensional arrays, only the first array dimension is  removed[.](#tab:meta.trans.arr-row-2-column-2-sentence-2)<br>For a type âarray of const Uâ, the resulting type is  const U[.](#tab:meta.trans.arr-row-2-column-2-sentence-3) â *end note*] |
| [ð](#tab:meta.trans.arr-row-3)<br>template<class T>   struct remove_all_extents; | If T is âmultidimensional array of Uâ, the resulting member  typedef type denotes U, otherwise T[.](#tab:meta.trans.arr-row-3-column-2-sentence-1) |

[2](#arr-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2182)

[*Example [1](#arr-example-1)*: // the following assertions hold:static_assert(is_same_v<remove_extent_t<int>, int>);static_assert(is_same_v<remove_extent_t<int[2]>, int>);static_assert(is_same_v<remove_extent_t<int[2][3]>, int[3]>);static_assert(is_same_v<remove_extent_t<int[][3]>, int[3]>); â *end example*]

[3](#arr-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2193)

[*Example [2](#arr-example-2)*: // the following assertions hold:static_assert(is_same_v<remove_all_extents_t<int>, int>);static_assert(is_same_v<remove_all_extents_t<int[2]>, int>);static_assert(is_same_v<remove_all_extents_t<int[2][3]>, int>);static_assert(is_same_v<remove_all_extents_t<int[][3]>, int>); â *end example*]

#### [21.3.9.6](#ptr) Pointer modifications [[meta.trans.ptr]](meta.trans.ptr)

[1](#ptr-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2206)

The templates specified in Table [61](#tab:meta.trans.ptr "Table 61: Pointer modifications") add or remove pointers[.](#ptr-1.sentence-1)

Table [61](#tab:meta.trans.ptr) — Pointer modifications [[tab:meta.trans.ptr]](./tab:meta.trans.ptr)  

| [ð](#tab:meta.trans.ptr-row-1)<br>**Template** | **Comments** |
| --- | --- |
| [ð](#tab:meta.trans.ptr-row-2)<br>template<class T>   struct remove_pointer; | If T has type â(possibly cv-qualified) pointer  to T1â then the member typedef type  denotes T1; otherwise, it denotes T[.](#tab:meta.trans.ptr-row-2-column-2-sentence-1) |
| [ð](#tab:meta.trans.ptr-row-3)<br>template<class T>   struct add_pointer; | If T is a referenceable type ([[defns.referenceable]](defns.referenceable "3.45 referenceable type")) or a  cv void type then  the member typedef type denotes  remove_reference_t<T>*;  otherwise, type denotes T[.](#tab:meta.trans.ptr-row-3-column-2-sentence-1) |

#### [21.3.9.7](#other) Other transformations [[meta.trans.other]](meta.trans.other)

[1](#other-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2238)

The templates specified in Table [62](#tab:meta.trans.other "Table 62: Other transformations") perform other modifications of a type[.](#other-1.sentence-1)

Table [62](#tab:meta.trans.other) — Other transformations [[tab:meta.trans.other]](./tab:meta.trans.other)  

| [ð](#tab:meta.trans.other-row-1)<br>**Template** | **Comments** |
| --- | --- |
| [ð](#tab:meta.trans.other-row-2)<br>template<class T>   struct [type_identity](#lib:type_identity "21.3.9.7 Other transformations [meta.trans.other]"); | The member typedef type denotes T[.](#tab:meta.trans.other-row-2-column-2-sentence-1) |
| [ð](#tab:meta.trans.other-row-3)<br>template<class T>   struct [remove_cvref](meta.reflection.traits#lib:remove_cvref "21.4.17 Reflection type traits [meta.reflection.traits]"); | The member typedef type denotes  [remove_cv_t](meta.type.synop#lib:remove_cv_t "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<[remove_reference_t](meta.type.synop#lib:remove_reference_t "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<T>>[.](#tab:meta.trans.other-row-3-column-2-sentence-1) |
| [ð](#tab:meta.trans.other-row-4)<br>template<class T>   struct [decay](meta.reflection.traits#lib:decay "21.4.17 Reflection type traits [meta.reflection.traits]"); | Let U be [remove_reference_t](meta.type.synop#lib:remove_reference_t "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<T>[.](#tab:meta.trans.other-row-4-column-2-sentence-1)<br>If [is_array_v](meta.type.synop#lib:is_array_v "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<U> is  true, the member typedef type denotes  [remove_extent_t](meta.type.synop#lib:remove_extent_t "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<U>*[.](#tab:meta.trans.other-row-4-column-2-sentence-2)<br>If [is_function_v](meta.type.synop#lib:is_function_v "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<U> is true,  the member typedef type denotes [add_pointer_t](meta.type.synop#lib:add_pointer_t "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<U>[.](#tab:meta.trans.other-row-4-column-2-sentence-3)<br>Otherwise  the member typedef type denotes [remove_cv_t](meta.type.synop#lib:remove_cv_t "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<U>[.](#tab:meta.trans.other-row-4-column-2-sentence-4)<br>[*Note [1](#tab:meta.trans.other-row-4-column-2-note-1)*:<br>This behavior is similar to the lvalue-to-rvalue ([[conv.lval]](conv.lval "7.3.2 Lvalue-to-rvalue conversion")), array-to-pointer ([[conv.array]](conv.array "7.3.3 Array-to-pointer conversion")), and function-to-pointer ([[conv.func]](conv.func "7.3.4 Function-to-pointer conversion")) 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[.](#tab:meta.trans.other-row-4-column-2-sentence-5) â *end note*] |
| [ð](#tab:meta.trans.other-row-5)<br>template<bool B, class T = void> struct [enable_if](#lib:enable_if "21.3.9.7 Other transformations [meta.trans.other]"); | If B is true, the member typedef type  denotes T; otherwise, there shall be no member  type[.](#tab:meta.trans.other-row-5-column-2-sentence-1) |
| [ð](#tab:meta.trans.other-row-6)<br>template<bool B, class T,class F>   struct [conditional](#lib:conditional "21.3.9.7 Other transformations [meta.trans.other]"); | If B is true, the member typedef type denotes T[.](#tab:meta.trans.other-row-6-column-2-sentence-1)<br>If B is false, the member typedef type denotes F[.](#tab:meta.trans.other-row-6-column-2-sentence-2) |
| [ð](#tab:meta.trans.other-row-7)<br>template<class... T> struct common_type; | Unless this trait is specialized,  the member type is defined or omitted as specified below[.](#tab:meta.trans.other-row-7-column-2-sentence-1)<br>If it is omitted, there shall be no member type[.](#tab:meta.trans.other-row-7-column-2-sentence-2)<br>Each type in the template parameter pack T shall be  complete, cv void, or an array of unknown bound[.](#tab:meta.trans.other-row-7-column-2-sentence-3) |
| [ð](#tab:meta.trans.other-row-8)<br>template<class, class,template<class> class,template<class> class>struct[basic_common_reference](refwrap.common.ref#lib:basic_common_reference "22.10.6.8 common_­reference related specializations [refwrap.common.ref]"); | Unless this trait is specialized,  there shall be no member type[.](#tab:meta.trans.other-row-8-column-2-sentence-1) |
| [ð](#tab:meta.trans.other-row-9)<br>template<class... T> struct [common_reference](meta.reflection.traits#lib:common_reference "21.4.17 Reflection type traits [meta.reflection.traits]"); | The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") type is defined or omitted  as specified below[.](#tab:meta.trans.other-row-9-column-2-sentence-1)<br>Each type in the parameter pack T shall  be complete or cv void[.](#tab:meta.trans.other-row-9-column-2-sentence-2) |
| [ð](#tab:meta.trans.other-row-10)<br>template<class T>   struct [underlying_type](meta.reflection.traits#lib:underlying_type "21.4.17 Reflection type traits [meta.reflection.traits]"); | If T is an enumeration type, the member typedef type denotes  the underlying type of T ([[dcl.enum]](dcl.enum "9.8.1 Enumeration declarations"));  otherwise, there is no member type[.](#tab:meta.trans.other-row-10-column-2-sentence-1)<br>   *Mandates*: T is not an incomplete enumeration type[.](#tab:meta.trans.other-row-10-column-2-sentence-2) |
| [ð](#tab:meta.trans.other-row-11)<br>template<class Fn,   class... ArgTypes>   struct [invoke_result](meta.reflection.traits#lib:invoke_result "21.4.17 Reflection type traits [meta.reflection.traits]"); | If the expression *INVOKE*(declval<Fn>(), declval<ArgTypes>()...) ([[func.require]](func.require "22.10.4 Requirements"))  is well-formed when treated as an unevaluated operand ([[expr.context]](expr.context#term.unevaluated.operand "7.2.3 Context dependence")),  the member typedef type denotes the type  decltype(*INVOKE*(declval<Fn>(), declval<ArgTypes>()...));  otherwise, there shall be no member type[.](#tab:meta.trans.other-row-11-column-2-sentence-1)<br>Access checking is  performed as if in a context unrelated to Fn and  ArgTypes[.](#tab:meta.trans.other-row-11-column-2-sentence-2)<br>Only the validity of the immediate context of the  expression is considered[.](#tab:meta.trans.other-row-11-column-2-sentence-3)<br>[*Note [2](#tab:meta.trans.other-row-11-column-2-note-2)*:<br>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[.](#tab:meta.trans.other-row-11-column-2-sentence-4)<br>Such side effects are not in the âimmediate  contextâ and can result in the program being ill-formed[.](#tab:meta.trans.other-row-11-column-2-sentence-5) â *end note*]<br>*Preconditions*: Fn and all types in the template parameter pack ArgTypes  are complete types, cv void, or arrays of  unknown bound[.](#tab:meta.trans.other-row-11-column-2-sentence-6) |
| [ð](#tab:meta.trans.other-row-12)<br>template<class Fn, class Tuple>   struct [apply_result](#lib:apply_result "21.3.9.7 Other transformations [meta.trans.other]"); | If [*tuple-like*](tuple.like#concept:tuple-like "22.4.3 Concept tuple-like [tuple.like]")<Tuple> is true  and the expression  *INVOKE*(declval<Fn>(), *ELEMS-OF*(Tuple)...) ([[func.require]](func.require "22.10.4 Requirements"))  is well-formed  when treated as an unevaluated operand ([[expr.context]](expr.context#term.unevaluated.operand "7.2.3 Context dependence")),  the member typedef type denotes the type  decltype(*INVOKE*(declval<Fn>(), *ELEMS-OF*(Tuple)...));  otherwise, there shall be no member type[.](#tab:meta.trans.other-row-12-column-2-sentence-1)<br>Access checking is performed as if in a context unrelated to Fn  and Tuple[.](#tab:meta.trans.other-row-12-column-2-sentence-2)<br>Only the validity of the immediate context of the expression is considered[.](#tab:meta.trans.other-row-12-column-2-sentence-3)<br>[*Note [3](#tab:meta.trans.other-row-12-column-2-note-3)*:<br>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[.](#tab:meta.trans.other-row-12-column-2-sentence-4)<br>Such side effects are not in the âimmediate contextâ  and can result in the program being ill-formed[.](#tab:meta.trans.other-row-12-column-2-sentence-5) â *end note*]<br>*Preconditions*: Fn and Tuple are complete types, cv void,  or arrays of unknown bound[.](#tab:meta.trans.other-row-12-column-2-sentence-6) |
| [ð](#tab:meta.trans.other-row-13)<br>template<class T> struct [unwrap_reference](meta.reflection.traits#lib:unwrap_reference "21.4.17 Reflection type traits [meta.reflection.traits]"); | If T is  a specialization [reference_wrapper](refwrap.general#lib:reference_wrapper "22.10.6.1 General [refwrap.general]")<X> for some type X,  the member typedef type of unwrap_reference<T>  denotes X&,  otherwise type denotes T[.](#tab:meta.trans.other-row-13-column-2-sentence-1) |
| [ð](#tab:meta.trans.other-row-14)<br>template<class T> [unwrap_ref_decay](functional.syn#lib:unwrap_ref_decay "22.10.2 Header <functional> synopsis [functional.syn]"); | The member typedef type of unwrap_ref_decay<T>  denotes the type [unwrap_reference_t](meta.type.synop#lib:unwrap_reference_t "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<[decay_t](meta.type.synop#lib:decay_t "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<T>>[.](#tab:meta.trans.other-row-14-column-2-sentence-1) |

[2](#other-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2385)

In addition to being available via inclusion
of the <type_traits> header, the templatesunwrap_reference,unwrap_ref_decay,unwrap_reference_t, andunwrap_ref_decay_t are available
when the header <functional> ([[functional.syn]](functional.syn "22.10.2 Header <functional> synopsis")) is included[.](#other-2.sentence-1)

[3](#other-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2396)

Let:

- [(3.1)](#other-3.1)

*CREF*(A) be [add_lvalue_reference_t](meta.type.synop#lib:add_lvalue_reference_t "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<const [remove_reference_t](meta.type.synop#lib:remove_reference_t "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<A>>,

- [(3.2)](#other-3.2)

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

- [(3.3)](#other-3.3)

*COPYCV*(FROM, TO) be an alias for type TO with the addition of FROM's top-level cv-qualifiers,
  [*Example [1](#other-example-1)*:
  *COPYCV*(const int, volatile short) is an alias for const volatile short[.](#other-3.3.sentence-1)
 â *end example*]

- [(3.4)](#other-3.4)

*COND-RES*(X, Y) be decltype(false ? declval<X(&)()>()() : declval<Y(&)()>()())[.](#other-3.sentence-1)

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:

- [(3.5)](#other-3.5)

  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[.](#other-3.5.sentence-1)

- [(3.6)](#other-3.6)

  Otherwise, let C be [remove_reference_t](meta.type.synop#lib:remove_reference_t "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<*COMMON-REF*(X&, Y&)>&&[.](#other-3.6.sentence-1)
  If A and B are both rvalue reference types, C is well-formed, and [is_convertible_v](meta.type.synop#lib:is_convertible_v "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<A, C> && [is_convertible_v](meta.type.synop#lib:is_convertible_v "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<B, C> is true,
 then *COMMON-REF*(A, B) is C[.](#other-3.6.sentence-2)

- [(3.7)](#other-3.7)

  Otherwise, let D be *COMMON-REF*(const X&, Y&)[.](#other-3.7.sentence-1)
  If A is an rvalue
 reference and B is an lvalue reference and D is
 well-formed and [is_convertible_v](meta.type.synop#lib:is_convertible_v "21.3.3 Header <type_­traits> synopsis [meta.type.synop]")<A, D> is true, then *COMMON-REF*(A, B) is D[.](#other-3.7.sentence-2)

- [(3.8)](#other-3.8)

  Otherwise, if A is an lvalue reference and B is an rvalue reference, then *COMMON-REF*(A, B) is *COMMON-REF*(B, A)[.](#other-3.8.sentence-1)

- [(3.9)](#other-3.9)

  Otherwise, *COMMON-REF*(A, B) is ill-formed[.](#other-3.9.sentence-1)

If any of the types computed above is ill-formed, then*COMMON-REF*(A, B) is ill-formed[.](#other-3.sentence-3)

[4](#other-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2444)

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:

- [(4.1)](#other-4.1)

  If sizeof...(T) is zero, there shall be no member type[.](#other-4.1.sentence-1)

- [(4.2)](#other-4.2)

  If sizeof...(T) is one, let T0 denote the sole type
constituting the pack T[.](#other-4.2.sentence-1)
  The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") type shall denote the same
type, if any, as common_type_t<T0, T0>;
otherwise there shall be no member type[.](#other-4.2.sentence-2)

- [(4.3)](#other-4.3)

  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[.](#other-4.3.sentence-1)

  * [(4.3.1)](#other-4.3.1)

      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>[.](#other-4.3.1.sentence-1)

  * [(4.3.2)](#other-4.3.2)

      [*Note [4](#other-note-4)*:
      None of the following will apply if there is a specialization common_type<D1, D2>[.](#other-4.3.2.sentence-1)
 â *end note*]

  * [(4.3.3)](#other-4.3.3)

      Otherwise, ifdecay_t<decltype(false ? declval<D1>() : declval<D2>())> denotes a valid type, let C denote that type[.](#other-4.3.3.sentence-1)

  * [(4.3.4)](#other-4.3.4)

      Otherwise, if *COND-RES*(*CREF*(D1), *CREF*(D2)) denotes a type, let C denote the type decay_t<*COND-RES*(*CREF*(D1), *CREF*(D2))>[.](#other-4.3.4.sentence-1)

   In either case, the member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") type shall denote
the same type, if any, as C[.](#other-4.3.sentence-2)
  Otherwise, there shall be no member type[.](#other-4.3.sentence-3)

- [(4.4)](#other-4.4)

  If sizeof...(T) is greater than two,
let T1, T2, and R, respectively,
denote the first, second, and (pack of) remaining types constituting T[.](#other-4.4.sentence-1)
  Let C denote the same type, if any, as common_type_t<T1, T2>[.](#other-4.4.sentence-2)
  If there is such a type C, the member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") type shall denote the same type, if any, as common_type_t<C, R...>[.](#other-4.4.sentence-3)
  Otherwise, there shall be no member type[.](#other-4.4.sentence-4)

[5](#other-5)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2496)

Notwithstanding the provisions of [[meta.rqmts]](meta.rqmts "21.3.2 Requirements"), and
pursuant to [[namespace.std]](namespace.std "16.4.5.2.1 Namespace std"),
a program may specialize common_type<T1, T2> for types T1 and T2 such thatis_same_v<T1, decay_t<T1>> andis_same_v<T2, decay_t<T2>> are each true[.](#other-5.sentence-1)

[*Note [5](#other-note-5)*:

Such specializations are needed when only explicit conversions
are desired between the template arguments[.](#other-5.sentence-2)

â *end note*]

Such a specialization need not have a member named type,
but if it does,
the [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]") 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[.](#other-5.sentence-3)

Moreover, common_type_t<T1, T2> shall denote
the same type, if any, as does common_type_t<T2, T1>[.](#other-5.sentence-4)

No diagnostic is required for a violation of this Note's rules[.](#other-5.sentence-5)

[6](#other-6)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2516)

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

- [(6.1)](#other-6.1)

  If sizeof...(T) is zero, there shall be no member type[.](#other-6.1.sentence-1)

- [(6.2)](#other-6.2)

  Otherwise, if sizeof...(T) is one, let T0 denote the sole
 type in the pack T[.](#other-6.2.sentence-1)
  The member typedef type shall denote the
 same type as T0[.](#other-6.2.sentence-2)

- [(6.3)](#other-6.3)

  Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in the pack T[.](#other-6.3.sentence-1)
  Then
  * [(6.3.1)](#other-6.3.1)

      Let R be *COMMON-REF*(T1, T2)[.](#other-6.3.1.sentence-1)
      If T1 and T2 are reference types, R is well-formed, and is_convertible_v<add_pointer_t<T1>, add_pointer_t<R>> && is_convertible_v<add_pointer_t<T2>, add_pointer_t<R>> is true,
 then the member typedef type denotes R[.](#other-6.3.1.sentence-2)

  * [(6.3.2)](#other-6.3.2)

      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[.](#other-6.3.2.sentence-1)

  * [(6.3.3)](#other-6.3.3)

      Otherwise, if *COND-RES*(T1, T2) is well-formed,
 then the member typedef type denotes that type[.](#other-6.3.3.sentence-1)

  * [(6.3.4)](#other-6.3.4)

      Otherwise, if common_type_t<T1, T2> is well-formed, then the
 member typedef type denotes that type[.](#other-6.3.4.sentence-1)

  * [(6.3.5)](#other-6.3.5)

      Otherwise, there shall be no member type[.](#other-6.3.5.sentence-1)

- [(6.4)](#other-6.4)

  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[.](#other-6.4.sentence-1)
  Let C be the type common_reference_t<T1, T2>[.](#other-6.4.sentence-2)
  Then:
  * [(6.4.1)](#other-6.4.1)

      If there is such a type C, the member typedef type shall
 denote the same type, if any, as common_reference_t<C, Rest...>[.](#other-6.4.1.sentence-1)

  * [(6.4.2)](#other-6.4.2)

      Otherwise, there shall be no member type[.](#other-6.4.2.sentence-1)

[7](#other-7)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2562)

Notwithstanding the provisions of [[meta.rqmts]](meta.rqmts "21.3.2 Requirements"), and
pursuant to [[namespace.std]](namespace.std "16.4.5.2.1 Namespace std"), a program may partially specializebasic_common_reference<T, U, TQual, UQual> for types T and U such thatis_same_v<T, decay_t<T>> andis_same_v<U, decay_t<U>> are each true[.](#other-7.sentence-1)

[*Note [6](#other-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[.](#other-7.sentence-2)

â *end note*]

Such a specialization need not have a member named type, but if it does,
the [*qualified-id*](expr.prim.id.qual#nt:qualified-id "7.5.5.3 Qualified names [expr.prim.id.qual]")basic_common_reference<T, U, TQual, UQual>​::​type shall denote a type
to which each of the types TQual<T> andUQual<U> is convertible[.](#other-7.sentence-3)

Moreover, basic_common_reference<T, U, TQual, UQual>​::​type shall denote
the same type, if any, as doesbasic_common_reference<U, T, UQual, TQual>​::​type[.](#other-7.sentence-4)

No diagnostic is required for a violation of these rules[.](#other-7.sentence-5)

[8](#other-8)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/meta.tex#L2586)

[*Example [2](#other-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*]
