Files
2025-10-25 03:02:53 +03:00

396 lines
32 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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.2Requirements[meta.rqmts]") ([[meta.rqmts]](meta.rqmts "21.3.2Requirements"))[.](#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.5CV-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.45referenceable 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.3References"))[.](#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.3References"))[.](#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.2Fundamental 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.6Conversion 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.2Fundamental 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.6Conversion 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.45referenceable 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.7Other 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.17Reflection type traits[meta.reflection.traits]"); | The member typedef type denotes [remove_cv_t](meta.type.synop#lib:remove_cv_t "21.3.3Header <type_­traits> synopsis[meta.type.synop]")<[remove_reference_t](meta.type.synop#lib:remove_reference_t "21.3.3Header <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.17Reflection type traits[meta.reflection.traits]"); | Let U be [remove_reference_t](meta.type.synop#lib:remove_reference_t "21.3.3Header <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.3Header <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.3Header <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.3Header <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.3Header <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.3Header <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.2Lvalue-to-rvalue conversion")), array-to-pointer ([[conv.array]](conv.array "7.3.3Array-to-pointer conversion")), and function-to-pointer ([[conv.func]](conv.func "7.3.4Function-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.7Other 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.7Other 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.8common_­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.17Reflection type traits[meta.reflection.traits]"); | The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The 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.17Reflection 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.1Enumeration 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.17Reflection type traits[meta.reflection.traits]"); | If the expression *INVOKE*(declval<Fn>(), declval<ArgTypes>()...) ([[func.require]](func.require "22.10.4Requirements")) is well-formed when treated as an unevaluated operand ([[expr.context]](expr.context#term.unevaluated.operand "7.2.3Context 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.7Other transformations[meta.trans.other]"); | If [*tuple-like*](tuple.like#concept:tuple-like "22.4.3Concept tuple-like[tuple.like]")<Tuple> is true and the expression *INVOKE*(declval<Fn>(), *ELEMS-OF*(Tuple)...) ([[func.require]](func.require "22.10.4Requirements")) is well-formed when treated as an unevaluated operand ([[expr.context]](expr.context#term.unevaluated.operand "7.2.3Context 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.17Reflection type traits[meta.reflection.traits]"); | If T is a specialization [reference_wrapper](refwrap.general#lib:reference_wrapper "22.10.6.1General[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.2Header <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.3Header <type_­traits> synopsis[meta.type.synop]")<[decay_t](meta.type.synop#lib:decay_t "21.3.3Header <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.2Header <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.3Header <type_­traits> synopsis[meta.type.synop]")<const [remove_reference_t](meta.type.synop#lib:remove_reference_t "21.3.3Header <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.3Header <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.3Header <type_­traits> synopsis[meta.type.synop]")<A, C> && [is_convertible_v](meta.type.synop#lib:is_convertible_v "21.3.3Header <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.3Header <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.4The 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.4The 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.4The 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.2Requirements"), and
pursuant to [[namespace.std]](namespace.std "16.4.5.2.1Namespace 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.3Qualified 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.2Requirements"), and
pursuant to [[namespace.std]](namespace.std "16.4.5.2.1Namespace 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.3Qualified 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*]