*This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.*

`decay_t`

in the new `common_type`

fallback should be `remove_cvref_t`

**Section:** 21.3.8.7 [meta.trans.other] **Status:** New
**Submitter:** Casey Carter **Opened:** 2019-05-12 **Last modified:** 2022-04-25

**Priority: **3

**View all other** issues in [meta.trans.other].

**View all issues with** New status.

**Discussion:**

P0898R4 "The One Ranges Proposal" added a new fallback case to
the definition of `common_type`

in 21.3.8.7 [meta.trans.other], bullet 3.3.4:

Otherwise, if

`denotes a type, let`

COND_RES(CREF(D1),CREF(D2))`C`

denote the type`decay_t<`

.COND_RES(CREF(D1),CREF(D2))>

Per para 3.3, `D1`

and `D2`

are decayed types. If both are `void`

, bullet 3.3.4
is not reached. If either is an abominable function type or `void`

, the

type expression above is ill-formed and bullet 3.3.4 does not apply. In all cases in which the
*COND_RES*

expression is well-formed, *COND_RES*`D1`

and `D2`

denote *cv*-unqualified
non-array object types. Given that fact, (1)

and *CREF*(D1)

are equivalent to *CREF*(D2)`const D1&`

and `const D2&`

, respectively, and (2) the

expression is equivalent to *COND_RES*```
decltype(false ?
declval<const D1&>() : declval<const D1&>())
```

, i.e., the second and third
operands of the conditional operator are lvalues of type `const D1`

and `const D2`

, respectively.

[expr.cond]/3 cannot apply since the operands are not glvalue bit-fields.

If `D1`

and `D2`

are the same type, [expr.cond]/4 does not apply. If `D1`

and
`D2`

are different types, there are a few cases to consider:

If [expr.cond]/4.1 applies, one operand is converted into an lvalue reference to the type of the other, i.e., both resulting operands are lvalues of type either

`const D1`

or`const D2`

.[expr.cond]/4.2 cannot apply since neither operand is an xvalue.

[expr.cond]/4.3.1 cannot apply since it would imply that the operands have the same type.

If [expr.cond]/4.3.2 applies — if either

`D1`

or`D2`

is a base class of the other — again the resulting operands are lvalues of type either`const D1`

or`const D2`

.If [expr.cond]/4.3.3 applies, the either the

`const D1&`

operand converts to`const D2`

or the`const D2&`

operand converts to`const D1`

.If none of the sub-bullets in [expr.cond]/4 applies, the operands are left unchanged.

[expr.cond]/5 applies if the operands initially had the same type, or in cases 1 and 4 above. The
conditional expression is an lvalue of type `const D1`

or `const D2`

, and the

expression yields *COND_RES*`const D1&`

or `const D2&`

.

Only cases 5 and 6 reach [expr.cond]/6. This paragraph performs overload resolution, which may result in converting both operands to the same non-class type to invoke a builtin conditional operator "overload".

[expr.cond]/7 applies standard conversions including array-to-pointer and function-to-pointer conversion to the operands. Consequently, the operands are once more "decayed" if [expr.cond]/6 converted them to an array or function type. Again case-by-case:

[expr.cond]/7.1 applies if the operands now have the same type, which is the type of the conditional expression.

[expr.cond]/7.2 applies if the operands have arithmetic or enumeration type; the conditional expression yields the result of applying the usual arithmetic conversions.

[expr.cond]/7.3 applies if the operands have pointer type; the conditional expression yields their composite pointer type.

[expr.cond]/7.4 applies if the operands have pointer-to-member type; the conditional expression applies some more standard conversions and yields their composite pointer type.

[expr.cond]/7.5 applies if one operand has type

`nullptr_t`

and the other is either a null pointer constant or has type`nullptr_t`

; the conditional expression yields`nullptr_t`

.

In every case above, the conditional expression is either ill-formed, an lvalue of type `const D1`

or
`const D2`

, or a prvalue of a non-array non-function type. Consequently the

type expression always yields a non-array non-function type, for which *COND_RES*`decay_t`

and `remove_cvref_t`

are equivalent. We can therefore replace

in
[meta.trans.other]/3.3.4 with *COND_RES*(*CREF*(D1), *CREF*(D2))```
decltype(false ? declval<const D1&>() :
declval<const D2&>())
```

, and replace the usage of `decay_t`

with `remove_cvref_t`

.

Furthermore, there are now quite a few different cases describing the behavior of `common_type`

.
It's not clear that `common_type<T...>::type`

is always a decayed type without in-depth analysis.
We should non-normatively clarify that fact.

*[2019-06-12 Priority set to 3 after reflector discussion]*

*[2020-05-01; Daniel adjusts wording to recent working draft]*

*[2022-04-25; Daniel adjusts wording to recent working draft]*

**Proposed resolution:**

This wording is relative to N4910.

Modify 21.3.8.7 [meta.trans.other] as indicated:

-2- Let:

~~(2.1) —~~

be*CREF*(A)`add_lvalue_reference_t<const remove_reference_t<A>>`

,(2.2) — […]

[…]

(2.9) — […]

If any of the types computed above is ill-formed, then

is ill-formed.*COMMON-REF*(A, B)-3- Note A: 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:(3.1) — […]

(3.2) — […]

(3.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.(3.3.1) — […]

(3.3.2) — […]

(3.3.3) — Otherwise, if

decay_t<decltype(false ? declval<D1>() : declval<D2>())>

denotes a valid type, let

`C`

denote that type.(3.3.4) — Otherwise, if

*COND-RES*(*CREF*(D1),*CREF*(D2))remove_cvref_t<decltype(false ? declval<const D1&>() : declval<const D2&>())>

denotes a type, let

`C`

denote th~~e~~at type.`decay_t<`

*COND-RES*(*CREF*(D1),*CREF*(D2))>

(3.4) — […]

[

*Note:*Whenever the*qualified-id*`common_type<T...>::type`

is valid, it denotes the same type as`decay_t<common_type<T...>::type>`

. —*end note*]-4- Note B: […]