# std::tuple<Types...>::tuple

< cpp‎ | utility‎ | tuple

定义于头文件 `<tuple>` |  |
constexpr tuple(); | (1) | (C++11 起) (条件性 `explicit`)
tuple( const Types&... args ); | (2) | (C++11 起) (C++14 起为 `constexpr`) (条件性 `explicit`)
template< class... UTypes > tuple( UTypes&&... args ); | (3) | (C++11 起) (C++14 起为 `constexpr`) (条件性 `explicit`)
template< class... UTypes > tuple( const tuple<UTypes...>& other ); | (4) | (C++11 起) (C++14 起为 `constexpr`) (条件性 `explicit`)
template <class... UTypes> tuple( tuple<UTypes...>&& other ); | (5) | (C++11 起) (C++14 起为 `constexpr`) (条件性 `explicit`)
template< class U1, class U2 > tuple( const pair<U1,U2>& p ); | (6) | (C++11 起) (C++14 起为 `constexpr`) (条件性 `explicit`)
template< class U1, class U2 > tuple( pair<U1,U2>&& p ); | (7) | (C++11 起) (C++14 起为 `constexpr`) (条件性 `explicit`)
tuple( const tuple& other ) = default; | (8) | (C++11 起)
tuple( tuple&& other ) = default; | (9) | (C++11 起)
template< class Alloc > tuple( std::allocator_arg_t, const Alloc& a ); | (10) | (C++11 起) (C++20 起为 `constexpr`) (条件性 `explicit`)
template< class Alloc > tuple( std::allocator_arg_t, const Alloc& a, const Types&... args ); | (11) | (C++11 起) (C++20 起为 `constexpr`) (条件性 `explicit`)
template< class Alloc, class... UTypes > tuple( std::allocator_arg_t, const Alloc& a, UTypes&&... args ); | (12) | (C++11 起) (C++20 起为 `constexpr`) (条件性 `explicit`)
template <class Alloc, class... UTypes> tuple( std::allocator_arg_t, const Alloc& a, const tuple<UTypes...>& other ); | (13) | (C++11 起) (C++20 起为 `constexpr`) (条件性 `explicit`)
template< class Alloc, class... UTypes > tuple( std::allocator_arg_t, const Alloc& a, tuple<UTypes...>&& other ); | (14) | (C++11 起) (C++20 起为 `constexpr`) (条件性 `explicit`)
template< class Alloc, class U1, class U2 > tuple( std::allocator_arg_t, const Alloc& a, const pair<U1, U2>& p ); | (15) | (C++11 起) (C++20 起为 `constexpr`) (条件性 `explicit`)
template< class Alloc, class U1, class U2 > tuple( std::allocator_arg_t, const Alloc& a, pair<U1, U2>&& p ); | (16) | (C++11 起) (C++20 起为 `constexpr`) (条件性 `explicit`)
template< class Alloc > tuple( std::allocator_arg_t, const Alloc& a, const tuple& other ); | (17) | (C++11 起) (C++20 起为 `constexpr`)
template< class Alloc > tuple( std::allocator_arg_t, const Alloc& a, tuple&& other ); | (18) | (C++11 起) (C++20 起为 `constexpr`)

构造新的 `tuple` 。

1) 默认构造函数。值初始化所有元素，若存在。若 sizeof...(Types) == 0 则默认构造函数为平凡。

- 此重载仅若 std::is_default_constructible<Ti>::value 对所有 `i` 为 true 才参与重载决议。
- 构造函数若且唯若对至少一个 `i` 有 `Ti` 不可从 {} 复制列表初始化才为 explicit 。

2) 直接构造函数。以对应参数初始化 tuple 的每个元素。

- 此重载仅若 sizeof...(Types) >= 1 与 std::is_copy_constructible<Ti>::value 对所有 `i` 为 true 才参与重载决议。
- 此构造函数若且唯若 std::is_convertible<const Ti&, Ti>::value 对至少一个 `i` 为 false 才为 explicit 。

3) 转换构造函数。以 std::forward<UTypes>(args) 中的对应值初始化 tuple 的每个元素。

- 此重载仅若 sizeof...(Types) == sizeof...(UTypes) 且 sizeof...(Types) >= 1 与 std::is_constructible<Ti, Ui&&>::value 对所有 `i` 为 true 才参与重载决议。
- 构造函数若且唯若才 std::is_convertible<Ui&&, Ti>::value 对至少一个 i 为 false 为 explicit 。

4) 转换复制构造函数。对 sizeof...(UTypes) 中所有 `i` ，以 std::get<i>(other) 初始化 tuple 的第 i 个元素。

- 此重载仅若
  - sizeof...(Types) == sizeof...(UTypes) 且
  - std::is_constructible_v<Ti, const Ui&> 对所有 `i` 为 true 且
  - 以下之一成立
    - sizeof...(Types) != 1 或
    - （ `Types...` 展开成 `T` 且 `UTypes...` 展开成 `U` 时） std::is_convertible_v<const tuple<U>&, T> 、 std::is_constructible_v<T, const tuple<U>&> 与 std::is_same_v<T, U> 均为 `false` 才参与重载决议。
- 构造函数若且唯若 std::is_convertible<const Ui&, Ti>::value 对至少一个 `i` 为 false 才为 explicit 。

5) 转换移动构造函数。对 sizeof...(UTypes) 中所有 `i` ，以 std::forward<Ui>(std::get<i>(other)) 初始化 tuple 的第 i 个元素。

- 此重载仅若
  - sizeof...(Types) == sizeof...(UTypes) 且
  - std::is_constructible_v<Ti, Ui&&> 对所有 `i` 为 true 且
  - 以下之一成立
    - sizeof...(Types) != 1 或
    - （ `Types...` 展开成 `T` 且 `UTypes...` 展开成 `U` 时） std::is_convertible_v<tuple<U>, T> 、 std::is_constructible_v<T, tuple<U>> 与 std::is_same_v<T, U> 均为 `false` 才参与重载决议。
- 构造函数若且唯若 std::is_convertible<Ui&&, Ti>::value 对至少一个 `i` 为 false 才为 explicit 。

6) pair 复制构造函数。构造 2-tuple ，从 `p.first` 构造第一个元素，从 `p.second` 构造第二个元素。

- 此重载仅若 sizeof...(Types) == 2 与 std::is_constructible<T0,const U1&>::value 与 std::is_constructible<T1, const U2&>::value 均为 true 才参与重载决议。
- 构造函数若且唯若 std::is_convertible<const U1&, T0>::value 或 std::is_convertible<const U2&, T1>::value 为 false 才为 explicit 。

7) pair 移动构造函数。构造 2-tuple ，从 std::forward<U1>(p.first) 构造第一个元素，从 std::forward<U2>(p.second) 构造第二个元素。

- 此重载仅若 sizeof...(Types) == 2 与 std::is_constructible<T0, U1&&>::value 与 std::is_constructible<T1, U2&&>::value 均为 true 才参与重载决议。
- 构造函数若且唯若 std::is_convertible<U1&&, T0>::value 或 std::convertible<U2&&, T1>::value 为 false 才为 explicit 。

8) 隐式定义的复制构造函数。以 `other` 的对应元素初始化 tuple 的每个元素。

- 若此函数进行的每个操作都是 constexpr ，则它是 constexpr 。对于空 tuple std::tuple<> ，它是 constexpr 。
- std::is_copy_constructible<Ti>::value 必须对所有 `i` 为 true ，否则行为未定义 (C++20 前)程序为谬构 (C++20 起)。

9) 隐式定义的移动构造函数。以 std::forward<Ui>(std::get<i>(other)) 构造 tuple 的第 i 个元素。
若此函数进行的每个操作都是 constexpr ，则它是 constexpr 。对于空 tuple std::tuple<> ，它是 constexpr 。

- std::is_move_constructible<Ti>::value 必须对所有 `i` 为 true ，否则行为未定义 (C++20 前)此重载不参与重载决议 (C++20 起)。

10-18) 等同于 (1-9) ，除了以使用分配器构造创建每个元素每个元素，即以分配器对象 `a` 为额外参数传递给每个 std::uses_allocator<Ui, Alloc>::value 为 true 的对象的构造函数。

### 参数

args | - | 用于初始化 `tuple` 每个元素的值
other | - | 用于初始化 `tuple` 每个元素的值的 `tuple`
p | - | 用于初始化此 2-tuple 的两个元素的值的 `pair`
a | - | 用于使用分配器构造的分配器

### 注解

条件性 explicit 的构造函数使得可以用列表初始化语法于复制初始化语境构造 tuple ：

    std::tuple<int, int> foo_tuple()
    {
      return {1, -1};  // N4387 前错误
      return std::make_tuple(1, -1); // 始终工作
    }

注意若列表中某元素不可隐式转换成目标 tuple 中的对应元素，则构造函数变为 explicit 。

    using namespace std::chrono;
    void launch_rocket_at(std::tuple<hours, minutes, seconds>);

    launch_rocket_at({hours(1), minutes(2), seconds(3)}); // OK
    launch_rocket_at({1, 2, 3}); // 错误： int 不可隐式转换成 duration
    launch_rocket_at(std::tuple<hours, minutes, seconds>{1, 2, 3}); // OK

### 示例

    #include <iostream>
    #include <string>
    #include <vector>
    #include <tuple>
    #include <memory>

    // 打印任何大小 tuple 的辅助函数
    template<class Tuple, std::size_t N>
    struct TuplePrinter {
        static void print(const Tuple& t)
        {
            TuplePrinter<Tuple, N-1>::print(t);
            std::cout << ", " << std::get<N-1>(t);
        }
    };

    template<class Tuple>
    struct TuplePrinter<Tuple, 1>{
        static void print(const Tuple& t)
        {
            std::cout << std::get<0>(t);
        }
    };

    template<class... Args>
    void print(const std::tuple<Args...>& t)
    {
        std::cout << "(";
        TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
        std::cout << ")\n";
    }
    // 辅助函数结束

    int main()
    {
        std::tuple<int, std::string, double> t1;
        std::cout << "Value-initialized: "; print(t1);
        std::tuple<int, std::string, double> t2(42, "Test", -3.14);
        std::cout << "Initialized with values: "; print(t2);
        std::tuple<char, std::string, int> t3(t2);
        std::cout << "Implicitly converted: "; print(t3);
        std::tuple<int, double> t4(std::make_pair(42, 3.14));
        std::cout << "Constructed from a pair"; print(t4);

        // 给出分配器 (Allocator) my_alloc ，带单参数构造函数 my_alloc(int)
        // 用 my_alloc(1) 于 vector 中分配 10 个 int
        std::vector<int, my_alloc> v(10, 1, my_alloc(1));
        // 用 my_alloc(2) 于 tuple 中的 vector 分配 10 个 int
        std::tuple<int, std::vector<int, my_alloc>, double> t5(std::allocator_arg,
                                                               my_alloc(2), 42, v,  -3.14);
    }

可能的输出：

    Value-initialized: (0, , 0)
    Initialized with values: (42, Test, -3.14)
    Implicitly converted: (*, Test, -3)
    Constructed from a pair(42, 3.14)

### 缺陷报告

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

DR | 应用于 | 出版时的行为 | 正确行为
--- | --- | --- | ---
N4387 | C++11 | 某些构造函数曾为 explicit ，阻止了有用的行为 | 使大多数构造函数为条件性 explicit
LWG 2510 | C++11 | 默认构造函数为隐式 | 使之为条件性 explicit
LWG 3158 | C++11 | 对应默认构造函数的使用分配器构造函数为隐式 | 使之为条件性 explicit
LWG 3211 | C++11 | 未指定 `tuple<>` 的默认构造函数是否为平凡 | 要求为平凡

### 参阅

make_tuple | 创建一个 `tuple` 对象，其类型根据各实参类型定义 (函数模板)
tie | 创建左值引用的 `tuple`，或将 tuple 解包为独立对象 (函数模板)
forward_as_tuple | 创建转发引用的 `tuple` (函数模板)