**Section:** 21.3.8.7 [meta.trans.other] **Status:** Resolved
**Submitter:** Eric Niebler **Opened:** 2015-01-12 **Last modified:** 2017-09-07 13:59:44 UTC

**Priority: **2

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

**View all issues with** Resolved status.

**Discussion:**

I think there's a defect regarding `common_type` and its specializations.
Unless I've missed it, there is nothing preventing folks from
instantiating `common_type` with *cv*-qualified types or reference types. In
fact, the wording in N3797 explicitly mentions *cv* `void`, so presumably at
least *cv* qualifications are allowed.

Users are given license to specialize `common_type` when at least of of
the types is user-defined. (A separate issue is the meaning of
user-defined. In core, I believe this is any class/struct/union/enum,
but in lib, I think it means any type not defined in std, right?) There
is at least one place in the standard that specializes `common_type`
(time.traits.specializations) on time_point and duration. But the
specializations are only for non-*cv*-qualified and non-reference
specializations of `time_point` and `duration`.

If the user uses, say, `common_type<duration<X,Y> const, duration<A,B>
const>`, they're not going to get the behavior they expect.

Suggest we clarify the requirements of `common_type`'s template
parameters. Also, perhaps we can add blanket wording that `common_type<A
[ cv][&], B [cv][&]>` is required to be equivalent to

Also, the change to make `common_type` SFINAE-friendly regressed key
functionality, as noted by Agustín K-ballo Bergé in
c++std-lib-37178.
Since `decay_t` is not applied until the very end of the type computation,
user specializations are very likely to to be found.

Agustín says:

Consider the following snippet:

struct X {}; struct Y { explicit Y(X){} }; namespace std { template<> struct common_type<X, Y> { typedef Y type; }; template<> struct common_type<Y, X> { typedef Y type; }; } static_assert(is_same<common_type_t<X, Y>, Y>()); // (A) static_assert(is_same<common_type_t<X, Y, Y>, Y>()); // (B) static_assert(is_same<common_type_t<X, X, Y>, Y>()); // (C)Under the original wording, all three assertion holds. Under the current wording,

(A) picks the user-defined specialization, so the assertion holds.

(B) goes to the third bullet and, ignoring the user-defined specialization, looks for

decltype(true ? declval<X>() : declval<Y>()); since it is ill-formed there is no common type.(C) goes to the third bullet and yields

common_type_t<X&&, Y>, which again misses the user-defined specialization.

The discussion following c++std-lib-35636
seemed to cohere around the idea that the primary `common_type` specialization should have the effect
of stripping top-level ref and *cv* qualifiers by applying `std::decay_t` to its arguments and,
if any of them change as a result of that transformation, re-dispatching to `common_type` on those transformed
arguments, thereby picking up any user-defined specializations. This change to `common_type` would make
the specializations in time.traits.specializations sufficient.

**Suggested wording**:

I'm afraid I don't know enough to suggest wording. But for exposition, the following is my best shot at implementing the suggested resolution. I believe it also fixes the regression noted by Agustín K-ballo Bergé in c++std-lib-37178.

namespace detail { template<typename T, typename U> using default_common_t = decltype(true? std::declval<T>() : std::declval<U>()); template<typename T, typename U, typename Enable = void> struct common_type_if {}; template<typename T, typename U> struct common_type_if<T, U, void_t<default_common_t<T, U>>> { using type = decay_t<default_common_t<T, U>>; }; template<typename T, typename U, typename TT = decay_t<T>, typename UU = decay_t<U>> struct common_type2 : common_type<TT, UU> // Recurse to catch user specializations {}; template<typename T, typename U> struct common_type2<T, U, T, U> : common_type_if<T, U> {}; template<typename Meta, typename Enable = void> struct has_type : std::false_type {}; template<typename Meta> struct has_type<Meta, void_t<typename Meta::type>> : std::true_type {}; template<typename Meta, typename...Ts> struct common_type_recurse : common_type<typename Meta::type, Ts...> {}; template<typename Meta, typename...Ts> struct common_type_recurse_if : std::conditional< has_type<Meta>::value, common_type_recurse<Meta, Ts...>, empty >::type {}; } template<typename ...Ts> struct common_type {}; template<typename T> struct common_type<T> { using type = std::decay_t<T>; }; template<typename T, typename U> struct common_type<T, U> : detail::common_type2<T, U> {}; template<typename T, typename U, typename... Vs> struct common_type<T, U, Vs...> : detail::common_type_recurse_if<common_type<T, U>, Vs...> {};

*[2016-08 Chicago]*

Walter and Nevin provide wording.

**Previous resolution [SUPERSEDED]:**

[This also resolves the first part of 2460]In Table 46 of N4604, entry for

common_type:... may specialize this trait if at least one template parameter in the specialization is a user-defined type and no template parameter is cv-qualified.

In [meta.trans.other] bullet 3.3:

... whose second operand is an xvalue of type

T1decay_t<T1>, and whose third operand is an xvalue of typeT2decay_t<T2>. If ...

*[2016-08-02, Chicago: Walt, Nevin, Rob, and Hal provide revised wording]*

**Previous resolution [SUPERSEDED]:**

This wording is relative to N4606.

[This also resolves the first part of LWG 2460]

In Table 46 — "Other transformations" edit the entry for

common_type:

Table 46 — Other transformations Template Comments …template <class... T>

struct common_type;The member typedef typeshall be defined or omitted as specified below.

If it is omitted, there shall be no membertype. All types in the

parameter packTshall be complete or (possiblycv)void.

A program may specialize this trait for twocv-unqualified non-reference types

if at least one~~template parameter in the specialization~~of them

is a user-defined type. [Note:Such specializations are

needed when only explicit conversions are desired among the template

arguments. —end note]…Edit 21.3.8.7 [meta.trans.other] p3 (and its subbullets) as shown below

For the

common_typetrait applied to a parameter packTof types, the membertypeshall be either defined or not present as follows:

If

sizeof...(T)is zero, there shall be no membertype.If

sizeof...(T)is one, letT0denote the sole type in the packT. The member typedeftypeshall denote the same type asdecay_t<T0>.If

sizeof...(T)is two, let`T1`

and`T2`

, respectively, denote the first and second types comprising`T`

, and let`D1`

and`D2`

, respectively, denote`decay_t<T1>`

and`decay_t<T2>`

.

If

`is_same_v<T1, D1>`

and`is_same_v<T2, D2>`

, and if there is no specialization`common_type<T1, T2>`

, let`C`

denote the type, if any, of an unevaluated conditional expression (7.6.16 [expr.cond]) whose first operand is an arbitrary value of type`bool`

, whose second operand is an xvalue of type`D1`

, and whose third operand is an xvalue of type`D2`

. If there is such a type`C`

, the member typedef`type`

shall denote`C`

. Otherwise, there shall be no member`type`

.If

`not is_same_v<T1, D1>`

or`not is_same_v<T2, D2>`

, the member typedef`type`

shall denote the same type, if any, ascommon_type_t<D1, D2>. Otherwise, there shall be no member`type`

.If

sizeof...(T)is greater than~~one~~two, letT1,T2, andR, respectively, denote the first, second, and (pack of) remaining types comprisingT.~~[~~LetNote:sizeof...(R)may be zero. —end note] LetCdenote the type, if any, of an unevaluated conditional expression (7.6.16 [expr.cond]) whose first operand is an arbitrary value of typebool, whose second operand is an xvalue of typeT1, and whose third operand is an xvalue of typeT2.`C`

denote`common_type_t<T1, T2>`

. If there is such a typeC, the member typedeftypeshall denote the same type, if any, ascommon_type_t<C, R...>. Otherwise, there shall be no membertype.

*[2016-08-03 Chicago LWG]*

LWG asks for minor wording tweaks and for an added Note. Walter revises the Proposed Resolution accordingly.

**Previous resolution [SUPERSEDED]:**

This wording is relative to N4606.

[This also resolves the first part of LWG 2460]

In Table 46 — "Other transformations" edit the entry for

common_type:

Table 46 — Other transformations Template Comments …template <class... T>

struct common_type;The member typedef typeshall be defined or omitted as specified below.

If it is omitted, there shall be no membertype. All types in the

parameter packTshall be complete or (possiblycv)void.

A program may specialize this trait for twocv-unqualified non-reference types

if at least one~~template parameter in the specialization~~of them

is a user-defined type. [Note:Such specializations are

needed when only explicit conversions are desired among the template

arguments. —end note]…Edit 21.3.8.7 [meta.trans.other] p3 (and its subbullets) as shown below

For the

common_typetrait applied to a parameter packTof types, the membertypeshall be either defined or not present as follows:

(3.1) — If

sizeof...(T)is zero, there shall be no membertype.(3.2) — If

sizeof...(T)is one, letT0denote the sole type in the packT. The member typedeftypeshall denote the same type asdecay_t<T0>.(3.3) — If

sizeof...(T)is two, let`T1`

and`T2`

, respectively, denote the first and second types comprising`T`

, and let`D1`

and`D2`

, respectively, denote`decay_t<T1>`

and`decay_t<T2>`

.

(3.3.1) — If

`is_same_v<T1, D1>`

and`is_same_v<T2, D2>`

, let`C`

denote the type of an unevaluated conditional expression (7.6.16 [expr.cond]) whose first operand is an arbitrary value of type`bool`

, whose second operand is an xvalue of type`D1`

, and whose third operand is an xvalue of type`D2`

. [Note:This will not apply if there is a specialization`common_type<D1, D2>`

. —end note](3.3.2) — Otherwise, let

`C`

denote the type`common_type_t<D1, D2>`

.In either case, if there is such a type

`C`

, the member typedef`type`

shall denote`C`

. Otherwise, there shall be no member`type`

.(3.4) — If

sizeof...(T)is greater than~~one~~two, letT1,T2, andR, respectively, denote the first, second, and (pack of) remaining types comprisingT.~~[~~LetNote:sizeof...(R)may be zero. —end note] LetCdenote the type, if any, of an unevaluated conditional expression (7.6.16 [expr.cond]) whose first operand is an arbitrary value of typebool, whose second operand is an xvalue of typeT1, and whose third operand is an xvalue of typeT2.`C`

denote`common_type_t<T1, T2>`

. If there is such a typeC, the member typedeftypeshall denote the same type, if any, ascommon_type_t<C, R...>. Otherwise, there shall be no membertype.

*[2016-08-04 Chicago LWG]*

Alisdair notes that 16.4.5.2.1 [namespace.std] p.1 seems to prohibit some kinds of specializations that we want to permit here and asks that the Table entry be augmented so as to specify the precise rules that a specialization is required to obey. Walter revises Proposed Resolution accordingly.

*[2016-08-03 Chicago]*

Fri PM: Move to Tentatively Ready

*[2016-08-11 Daniel comments]*

LWG 2763 presumably provides a superiour resolution that also fixes another bug in the Standard.

*[2016-08-12]*

Howard request to reopen this issue because of the problem pointed out by LWG 2763.

*[2016-08-13 Tim Song comments]*

In addition to the issue pointed out in LWG 2763, the current P/R no longer decays the type
of the conditional expression. However, that seems harmless since 7 [expr]/5 means that the
"type of an expression" is never a reference type, and 7.6.16 [expr.cond]'s rules appear to ensure that
the type of the conditional expression will never be "decay-able" when fed with two xvalues of cv-unqualified
non-array object type. Nonetheless, a note along the lines of "[*Note:* `C`

is never a reference,
function, array, or cv-qualified type. — *end note*]" may be appropriate, similar to the note
at the end of [dcl.decomp]/1.

*[2016-11-12, Issaquah]*

Resolved by P0435R1

**Proposed resolution:**

This wording is relative to N4606.

*[This also resolves the first part of LWG 2460]*

In Table 46 — "Other transformations" edit the entry for

`common_type`:Table 46 — Other transformations Template Comments `…``template <class... T>`

struct common_type;Unless this trait is specialized (as specified in Note B, below), t ~~T~~he

member typedef`type`shall be defined or omitted as specified in Note A, below.

If it is omitted, there shall be no member`type`. All types in the

parameter pack`T`shall be complete or (possibly*cv*)`void`.

~~A program may specialize this trait~~

if at least one template parameter in the specialization

is a user-defined type. [*Note:*Such specializations are

needed when only explicit conversions are desired among the template

arguments. —*end note*]`…`Edit 21.3.8.7 [meta.trans.other] p3 (and its subbullets) as shown below

-3- Note A: For the

`common_type`trait applied to a parameter pack`T`of types, the member`type`shall be either defined or not present as follows:(3.1) — If

`sizeof...(T)`is zero, there shall be no member`type`.(3.2) — If

`sizeof...(T)`is one, let`T0`denote the sole type in the pack`T`. The member typedef`type`shall denote the same type as`decay_t<T0>`.(3.3) — If

`sizeof...(T)`is two, let`T1`

and`T2`

, respectively, denote the first and second types comprising`T`

, and let`D1`

and`D2`

, respectively, denote`decay_t<T1>`

and`decay_t<T2>`

.(3.3.1) — If

`is_same_v<T1, D1>`

and`is_same_v<T2, D2>`

, let`C`

denote the type of an unevaluated conditional expression (7.6.16 [expr.cond]) whose first operand is an arbitrary value of type`bool`

, whose second operand is an xvalue of type`D1`

, and whose third operand is an xvalue of type`D2`

. [*Note:*This will not apply if there is a specialization`common_type<D1, D2>`

. —*end note*](3.3.2) — Otherwise, let

`C`

denote the type`common_type_t<D1, D2>`

.

In either case, if there is such a type

`C`

, the member typedef`type`

shall denote`C`

. Otherwise, there shall be no member`type`

.(3.4) — If

`sizeof...(T)`is greater than~~one~~two, let`T1`,`T2`, and`R`, respectively, denote the first, second, and (pack of) remaining types comprising`T`.~~[~~Let*Note:*`sizeof...(R)`may be zero. —*end note*] Let`C`denote the type, if any, of an unevaluated conditional expression (7.6.16 [expr.cond]) whose first operand is an arbitrary value of type`bool`, whose second operand is an xvalue of type`T1`, and whose third operand is an xvalue of type`T2`.`C`

denote`common_type_t<T1, T2>`

. If there is such a type`C`, the member typedef`type`shall denote the same type, if any, as`common_type_t<C, R...>`. Otherwise, there shall be no member`type`.

-?- Note B: A program may specialize the

`common_type`

trait for two*cv*-unqualified non-reference types if at least one of them is a user-defined type. [*Note:*Such specializations are needed when only explicit conversions are desired among the template arguments. —*end note*] Such a specialization need not have a member named`type`

, but if it does, that member shall be a*typedef-name*for a*cv*-unqualified non-reference type that need not otherwise meet the specification set forth in Note A, above.-4- [

*Example:*Given these definitions: […]