# std::common_type

< cpp‎ | types

定义于头文件 `<type_traits>` |  |
template< class... T > struct common_type; |  | (C++11 起)

确定所有类型 `T...` 的共用类型，即所有 `T...` 都能隐式转换到的类型。若这种类型（根据后述规则确定）存在，则成员 `type` 指名该类型。否则，无成员 `type` 。

- 若 sizeof...(T) 为零，则无成员 `type` 。
- 若 sizeof...(T) 为一（即 `T...` 只含一个类型 `T0` ），则成员 `type` 指名与 std::common_type<T0, T0>::type 相同的类型，若它存在；否则无成员 `type` 。
- 若 sizeof...(T) 为二（即 `T...` 含恰好二个成员 `T1` 与 `T2` ），则

  - 若应用 std::decay 到至少 `T1` 与 `T2` 中至少一个类型后产生相异类型，则成员 `type` 指名与 std::common_type<std::decay<T1>::type, std::decay<T2>::type>::type 相同的类型，若它存在；若不存在，则无成员 `type` 。
  - 否则，若有对 std::common_type<T1, T2> 的用户定义特化，则使用该特化；
  - 否则， 若 std::decay<decltype(false ? std::declval<T1>() : std::declval<T2>())>::type 是合法类型，则成员 `type` 代表该类型；

否则，若 std::decay<decltype(false ? std::declval<CR1>() : std::declval<CR2>())>::type 为合法类型，其中 `CR1` 与 `CR2` 分别为 const std::remove_reference_t<T1>& 与 const std::remove_reference_t<T2>&，则成员 `type` 代表该类型； | (C++20 起)

  - 否则，无成员 `type` 。

- 若 sizeof...(T) 大于二（即 `T...` 由类型 `T1, T2, R...` 组成），则若 std::common_type<T1, T2>::type 存在，则成员 `type` 指代 std::common_type<std::common_type<T1, T2>::type, R...>::type ，若存在这种类型。其他所有情况下，无成员 `type` 。

参数包 `T` 中的类型应均为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

### 成员类型

名称 | 定义
`type` | 所有 `T...` 的共用类型

### 辅助类型

template< class... T > using common_type_t = typename common_type<T...>::type; |  | (C++14 起)

### 特化

用户可为类型 `T1` 与 `T2` 特化 `common_type` ，只要

- `T1` 与 `T2` 至少一个依赖于用户定义类型，且
- std::decay 对于 `T1` 和 `T2` 都是同等变换。

若这种特化拥有名为 `type` 的成员，则有限定标识 std::common_type<T1, T2>::type 必须合法并指名一个 `T1` 和 `T2` 都能显式转换到的，无 cv 限定且非引用的类型。而且， std::common_type<T1, T2>::type 与 std::common_type<T2, T1>::type 必须指代同一类型。

以违背这些规则的方式添加 `common_type` 特化的程序拥有未定义行为。

注意添加特化到来自 `<type_traits>` 的任何其他模板（除了 `std::basic_common_reference` ） (C++20 起)的程序行为未定义。

标准库已提供下列特化：

std::common_type<std::chrono::duration> (C++11) | 特化 std::common_type 特征 (类模板特化)
std::common_type<std::chrono::time_point> (C++11) | 特化 std::common_type 特征 (类模板特化)

### 可能的实现

    // 主模板（用于零个类型）
    template<class...>
    struct common_type {};

    //////// 一个类型
    template<class T>
    struct common_type<T> : common_type<T, T> {};

    namespace detail {
    template<class...>
    using void_t = void;

    template<class T1, class T2>
    using conditional_result_t = decltype(false ? std::declval<T1>() : std::declval<T2>());

    template<class, class, class = void>
    struct decay_conditional_result {};
    template<class T1, class T2>
    struct decay_conditional_result<T1, T2, void_t<conditional_result_t<T1, T2>>>
        : std::decay<conditional_result_t<T1, T2>> {};

    template<class T>
    using add_cref_t = // C++20 起使用
        typename std::add_lvalue_reference<
            const typename std::remove_reference<T>::type>::type;

    template<class T1, class T2, class = void>
    struct common_type_2_impl : decay_conditional_result<add_cref_t<T1>, add_cref_t<T2>> {};

    // C++11 实现：
    // template<class, class, class = void>
    // struct common_type_2_impl {};

    template<class T1, class T2>
    struct common_type_2_impl<T1, T2, void_t<conditional_result_t<
        typename std::decay<T1>::type,
        typename std::decay<T2>::type>>>
        : decay_conditional_result<typename std::decay<T1>::type,
                                   typename std::decay<T2>::type> {};
    }

    //////// 二个类型
    struct common_type<T1, T2>
        : std::conditional<std::is_same<T1, typename std::decay<T1>::type>::value &&
                           std::is_same<T2, typename std::decay<T2>::type>::value,
                           detail::common_type_2_impl<T1, T2>,
                           common_type<typename std::decay<T1>::type,
                                       typename std::decay<T2>::type>>::type {};

    //////// 三个及以上类型
    namespace detail {
    template<class AlwaysVoid, class T1, class T2, class...R>
    struct common_type_multi_impl {};
    template<class T1, class T2, class...R>
    struct common_type_multi_impl<void_t<typename common_type<T1, T2>::type>, T1, T2, R...>
        : common_type<typename common_type<T1, T2>::type, R...> {};
    }

    template<class T1, class T2, class... R>
    struct common_type<T1, T2, R...>
        : detail::common_type_multi_impl<void, T1, T2, R...> {};

### 注解

对于不是提升目标的算术类型，共用类型可视为如 T0() + T1() + ... + Tn() 的（可以为混合模式的）算术表达式的类型。

### 示例

演示用户定义类上的混合模式算术

    #include <iostream>
    #include <type_traits>

    template <class T>
    struct Number { T n; };

    template <class T, class U>
    Number<typename std::common_type<T, U>::type> operator+(const Number<T>& lhs,
                                                            const Number<U>& rhs)
    {
        return {lhs.n + rhs.n};
    }

    int main()
    {
        Number<int> i1 = {1}, i2 = {2};
        Number<double> d1 = {2.3}, d2 = {3.5};
        std::cout << "i1i2: " << (i1 + i2).n << "\ni1d2: " << (i1 + d2).n << '\n'
                  << "d1i2: " << (d1 + i2).n << "\nd1d2: " << (d1 + d2).n << '\n';
    }

输出：

    i1i2: 3
    i1d2: 4.5
    d1i2: 4.3
    d1d2: 5.8

### 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
--- | --- | --- | ---
LWG 2141 | C++11 | common_type<int, int>::type 为 int&& | 退化了结果类型
LWG 2408 | C++11 | `common_type` 非 SFINAE 友好 | 令之为 SFINAE 友好
LWG 2460 | C++11 | `common_type` 特化的书写近乎不可能 | 减少了需要的特化数量