[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)
**Template** | **Comments** |
| --- | --- |
| [ð](#tab:meta.trans.cv-row-2)
template 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)
[*Example [1](#tab:meta.trans.cv-row-2-column-2-example-1)*:
remove_const_t evaluates to volatile int, whereas remove_const_t evaluates to const int*[.](#tab:meta.trans.cv-row-2-column-2-sentence-2) â *end example*] |
| [ð](#tab:meta.trans.cv-row-3)
template 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)
[*Example [2](#tab:meta.trans.cv-row-3-column-2-example-2)*:
remove_volatile_t evaluates to const int, whereas remove_volatile_t evaluates to volatile int*[.](#tab:meta.trans.cv-row-3-column-2-sentence-2) â *end example*] |
| [ð](#tab:meta.trans.cv-row-4)
template 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)
[*Example [3](#tab:meta.trans.cv-row-4-column-2-example-3)*:
remove_cv_t evaluates to int, whereas remove_cv_t evaluates to const volatile int*[.](#tab:meta.trans.cv-row-4-column-2-sentence-2) â *end example*] |
| [ð](#tab:meta.trans.cv-row-5)
template struct add_const; | The member typedef type denotes const T[.](#tab:meta.trans.cv-row-5-column-2-sentence-1)
[*Note [1](#tab:meta.trans.cv-row-5-column-2-note-1)*:
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)
template struct add_volatile; | The member typedef type denotes volatile T[.](#tab:meta.trans.cv-row-6-column-2-sentence-1)
[*Note [2](#tab:meta.trans.cv-row-6-column-2-note-2)*:
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)
template struct add_cv; | The member typedef type denotes add_const_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)
**Template** | **Comments** |
| --- | --- |
| [ð](#tab:meta.trans.ref-row-2)
template 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)
template 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)
[*Note [1](#tab:meta.trans.ref-row-3-column-2-note-1)*:
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)
template 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)
[*Note [2](#tab:meta.trans.ref-row-4-column-2-note-2)*:
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)
For example, when a type T is a reference type T1&, the type add_rvalue_reference_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)
**Template** | **Comments** |
| --- | --- |
| [ð](#tab:meta.trans.sign-row-2)
template 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)
*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)
template 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)
*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)
**Template** | **Comments** |
| --- | --- |
| [ð](#tab:meta.trans.arr-row-2)
template 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)
[*Note [1](#tab:meta.trans.arr-row-2-column-2-note-1)*:
For multidimensional arrays, only the first array dimension is removed[.](#tab:meta.trans.arr-row-2-column-2-sentence-2)
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)
template 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, int>);static_assert(is_same_v, int>);static_assert(is_same_v, int[3]>);static_assert(is_same_v, 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, int>);static_assert(is_same_v, int>);static_assert(is_same_v, int>);static_assert(is_same_v, 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)
**Template** | **Comments** |
| --- | --- |
| [ð](#tab:meta.trans.ptr-row-2)
template 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)
template 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*; 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)
**Template** | **Comments** |
| --- | --- |
| [ð](#tab:meta.trans.other-row-2)
template 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)
template 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 synopsis [meta.type.synop]")<[remove_reference_t](meta.type.synop#lib:remove_reference_t "21.3.3 Header synopsis [meta.type.synop]")>[.](#tab:meta.trans.other-row-3-column-2-sentence-1) |
| [ð](#tab:meta.trans.other-row-4)
template 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 synopsis [meta.type.synop]")[.](#tab:meta.trans.other-row-4-column-2-sentence-1)
If [is_array_v](meta.type.synop#lib:is_array_v "21.3.3 Header synopsis [meta.type.synop]") is true, the member typedef type denotes [remove_extent_t](meta.type.synop#lib:remove_extent_t "21.3.3 Header synopsis [meta.type.synop]")*[.](#tab:meta.trans.other-row-4-column-2-sentence-2)
If [is_function_v](meta.type.synop#lib:is_function_v "21.3.3 Header synopsis [meta.type.synop]") is true, the member typedef type denotes [add_pointer_t](meta.type.synop#lib:add_pointer_t "21.3.3 Header synopsis [meta.type.synop]")[.](#tab:meta.trans.other-row-4-column-2-sentence-3)
Otherwise the member typedef type denotes [remove_cv_t](meta.type.synop#lib:remove_cv_t "21.3.3 Header synopsis [meta.type.synop]")[.](#tab:meta.trans.other-row-4-column-2-sentence-4)
[*Note [1](#tab:meta.trans.other-row-4-column-2-note-1)*:
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)
template 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)
template 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)
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)
template 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)
If it is omitted, there shall be no member type[.](#tab:meta.trans.other-row-7-column-2-sentence-2)
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)
template class,template 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)
template 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)
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)
template 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)
*Mandates*: T is not an incomplete enumeration type[.](#tab:meta.trans.other-row-10-column-2-sentence-2) |
| [ð](#tab:meta.trans.other-row-11)
template struct [invoke_result](meta.reflection.traits#lib:invoke_result "21.4.17 Reflection type traits [meta.reflection.traits]"); | If the expression *INVOKE*(declval(), declval()...) ([[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(), declval()...)); otherwise, there shall be no member type[.](#tab:meta.trans.other-row-11-column-2-sentence-1)
Access checking is performed as if in a context unrelated to Fn and ArgTypes[.](#tab:meta.trans.other-row-11-column-2-sentence-2)
Only the validity of the immediate context of the expression is considered[.](#tab:meta.trans.other-row-11-column-2-sentence-3)
[*Note [2](#tab:meta.trans.other-row-11-column-2-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[.](#tab:meta.trans.other-row-11-column-2-sentence-4)
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*]
*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)
template 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]") is true and the expression *INVOKE*(declval(), *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(), *ELEMS-OF*(Tuple)...)); otherwise, there shall be no member type[.](#tab:meta.trans.other-row-12-column-2-sentence-1)
Access checking is performed as if in a context unrelated to Fn and Tuple[.](#tab:meta.trans.other-row-12-column-2-sentence-2)
Only the validity of the immediate context of the expression is considered[.](#tab:meta.trans.other-row-12-column-2-sentence-3)
[*Note [3](#tab:meta.trans.other-row-12-column-2-note-3)*:
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)
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*]
*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)
template 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]") for some type X, the member typedef type of unwrap_reference denotes X&, otherwise type denotes T[.](#tab:meta.trans.other-row-13-column-2-sentence-1) |
| [ð](#tab:meta.trans.other-row-14)
template [unwrap_ref_decay](functional.syn#lib:unwrap_ref_decay "22.10.2 Header synopsis [functional.syn]"); | The member typedef type of unwrap_ref_decay denotes the type [unwrap_reference_t](meta.type.synop#lib:unwrap_reference_t "21.3.3 Header synopsis [meta.type.synop]")<[decay_t](meta.type.synop#lib:decay_t "21.3.3 Header synopsis [meta.type.synop]")>[.](#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 header, the templatesunwrap_reference,unwrap_ref_decay,unwrap_reference_t, andunwrap_ref_decay_t are available
when the header ([[functional.syn]](functional.syn "22.10.2 Header 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 synopsis [meta.type.synop]") synopsis [meta.type.synop]")>,
- [(3.2)](#other-3.2)
*XREF*(A) denote a unary alias template T such that T 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()() : declval()())[.](#other-3.sentence-1)
Given types A and B,
let X be remove_reference_t,
let Y be remove_reference_t, 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 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 synopsis [meta.type.synop]") && [is_convertible_v](meta.type.synop#lib:is_convertible_v "21.3.3 Header synopsis [meta.type.synop]") 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 synopsis [meta.type.synop]") 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;
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 and decay_t, respectively[.](#other-4.3.sentence-1)
* [(4.3.1)](#other-4.3.1)
If is_same_v is false or is_same_v is false,
let C denote the same type, if any,
as common_type_t[.](#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[.](#other-4.3.2.sentence-1)
â *end note*]
* [(4.3.3)](#other-4.3.3)
Otherwise, ifdecay_t() : declval())> 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[.](#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[.](#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 for types T1 and T2 such thatis_same_v> andis_same_v> 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::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 shall denote
the same type, if any, as does common_type_t[.](#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> && is_convertible_v, add_pointer_t> 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,
*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 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[.](#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[.](#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 for types T and U such thatis_same_v> andis_same_v> 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::type shall denote a type
to which each of the types TQual andUQual is convertible[.](#other-7.sentence-3)
Moreover, basic_common_reference::type shall denote
the same type, if any, as doesbasic_common_reference::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, short>);static_assert(is_same_v, double>);static_assert(is_same_v, bool>);static_assert(is_same_v, int>, void>);static_assert(is_same_v, char&&>);static_assert(is_same_v, const char&>);
â *end example*]