[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*]