std::tuple<Types...>::tuple
来自 zh.cppreference.net
| 定义于头文件 <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 >
constexpr tuple( tuple<UTypes...>& other );
|
(4) | (C++23 起) (条件性 explicit) |
template< class... UTypes >
tuple( const tuple<UTypes...>& other );
|
(5) | (C++11 起) (C++14 起 constexpr) (条件性 explicit) |
template< class... UTypes >
tuple( tuple<UTypes...>&& other );
|
(6) | (C++11 起) (C++14 起 constexpr) (条件性 explicit) |
template< class... UTypes >
constexpr tuple( const tuple<UTypes...>&& other );
|
(7) | (C++23 起) (条件性 explicit) |
template< class U1, class U2 >
constexpr tuple( std::pair<U1, U2>& p );
|
(8) | (C++23 起) (条件性 explicit) |
template< class U1, class U2 >
tuple( const std::pair<U1, U2>& p );
|
(9) | (C++11 起) (C++14 起 constexpr) (条件性 explicit) |
template< class U1, class U2 >
tuple( std::pair<U1, U2>&& p );
|
(10) | (C++11 起) (C++14 起 constexpr) (条件性 explicit) |
template< class U1, class U2 >
constexpr tuple( const std::pair<U1, U2>&& p );
|
(11) | (C++23 起) (条件性 explicit) |
template< tuple-like UTuple >
constexpr tuple( UTuple&& u );
|
(12) | (C++23 起) (条件性 explicit) |
tuple( const tuple& other ) = default;
|
(13) | (C++11 起) |
tuple( tuple&& other ) = default;
|
(14) | (C++11 起) |
| 分配器扩展构造函数 |
||
template< class Alloc >
tuple( std::allocator_arg_t, const Alloc& a );
|
(15) | (C++11 起) (C++20 起 constexpr) (条件性 explicit) |
template< class Alloc >
tuple( std::allocator_arg_t, const Alloc& a,
const Types&... args );
|
(16) | (C++11 起) (C++20 起 constexpr) (条件性 explicit) |
template< class Alloc, class... UTypes >
tuple( std::allocator_arg_t, const Alloc& a,
UTypes&&... args );
|
(17) | (C++11 起) (C++20 起 constexpr) (条件性 explicit) |
template< class Alloc, class... UTypes >
constexpr tuple( std::allocator_arg_t, const Alloc& a,
tuple<UTypes...>& other );
|
(18) | (C++23 起) (条件性 explicit) |
template< class Alloc, class... UTypes >
tuple( std::allocator_arg_t, const Alloc& a,
const tuple<UTypes...>& other );
|
(19) | (C++11 起) (C++20 起 constexpr) (条件性 explicit) |
template< class Alloc, class... UTypes >
tuple( std::allocator_arg_t, const Alloc& a,
tuple<UTypes...>&& other );
|
(20) | (C++11 起) (C++20 起 constexpr) (条件性 explicit) |
template< class Alloc, class... UTypes >
constexpr tuple( std::allocator_arg_t, const Alloc& a,
const tuple<UTypes...>&& other );
|
(21) | (C++23 起) (条件性 explicit) |
template< class Alloc, class U1, class U2 >
constexpr tuple( std::allocator_arg_t, const Alloc& a,
std::pair<U1, U2>& p );
|
(22) | (C++23 起) (条件性 explicit) |
template< class Alloc, class U1, class U2 >
tuple( std::allocator_arg_t, const Alloc& a,
const std::pair<U1, U2>& p );
|
(23) | (C++11 起) (C++20 起 constexpr) (条件性 explicit) |
template< class Alloc, class U1, class U2 >
tuple( std::allocator_arg_t, const Alloc& a,
std::pair<U1, U2>&& p );
|
(24) | (C++11 起) (C++20 起 constexpr) (条件性 explicit) |
template< class Alloc, class U1, class U2 >
constexpr tuple( std::allocator_arg_t, const Alloc& a,
const std::pair<U1, U2>&& p );
|
(25) | (C++23 起) (条件性 explicit) |
template< class Alloc, tuple-like UTuple >
constexpr tuple( std::allocator_arg_t, const Alloc& a, UTuple&& u );
|
(26) | (C++23 起) (条件性 explicit) |
template< class Alloc >
tuple( std::allocator_arg_t, const Alloc& a,
const tuple& other );
|
(27) | (C++11 起) (C++20 起 constexpr) |
template< class Alloc >
tuple( std::allocator_arg_t, const Alloc& a,
tuple&& other );
|
(28) | (C++11 起) (C++20 起 constexpr) |
构造一个新的 tuple。
在下面的描述中,令
i在范围[0,sizeof...(Types))内,顺序排列,Ti为i中的第Types个类型,且Ui为名为i的模板参数包中的第UTypes个类型,
其中索引从零开始。
1) 默认构造函数。值初始化所有元素(如果有的话)。如果
sizeof...(Types) == 0,则默认构造函数是平凡的。
- 此重载仅当对于所有
std::is_default_constructible<Ti>::value,true为i时参与重载决议。 - 当且仅当对于至少一个
explicit,Ti不能从{}进行拷贝列表初始化时,该构造函数为i。
2) 直接构造函数。用对应的参数初始化 tuple 的每个元素。
- 此重载仅当
sizeof...(Types) >= 1且对于所有std::is_copy_constructible<Ti>::value,true为i时参与重载决议。 - 当且仅当对于至少一个
explicit,std::is_convertible<const Ti&, Ti>::value为false时,该构造函数为i。
3) 转换构造函数。用
std::forward<UTypes>(args) 中对应的值初始化 tuple 的每个元素。
- 此重载仅当以下条件全部满足时参与重载决议:
sizeof...(Types) == sizeof...(UTypes),sizeof...(Types) >= 1,std::is_constructible<Ti, Ui>::value对于所有true为i,且- 令
D为std::decay<U0>::type(C++20 前)std::remove_cvref_t<U0>(C++20 起),- 如果
sizeof...(Types) == 1,那么D不是std::tuple,否则, - 如果
sizeof...(Types) == 2或sizeof...(Types) == 3,那么要么D不是 std::allocator_arg_t,要么T0是 std::allocator_arg_t。
- 如果
- 当且仅当对于至少一个
explicit,std::is_convertible<Ui, Ti>::value为false时,该构造函数为i。
|
(C++23 起) |
4-7) 转换构造函数。用
other 的对应元素初始化 tuple 的每个元素。
正式地,令 FWD(other) 为 std::forward<decltype(other)>(other),对于所有 i,初始化 tuple 的第 i 个元素为 std::get<i>(FWD(other))。
- 此重载仅当以下条件全部满足时参与重载决议:
sizeof...(Types) == sizeof...(UTypes),std::is_constructible_v<Ti, decltype(std::get<i>(FWD(other)))>对于所有true为i,且- 要么
sizeof...(Types)不是1,要么- (当
Types...展开为T且UTypes...展开为U时)std::is_convertible_v<decltype(other), T>、std::is_constructible_v<T, decltype(other)>和std::is_same_v<T, U>均为false。
- 当且仅当对于至少一个
explicit,std::is_convertible_v<decltype(std::get<i>(FWD(other))), Ti>为false时,这些构造函数为i。
|
(C++23 起) |
8-11) pair 构造函数。构造一个 2 元素 tuple,每个元素从
p 的对应元素构造。
正式地,令 FWD(p) 为 std::forward<decltype(p)>(p),用 std::get<0>(FWD(p)) 初始化第一个元素,用 std::get<1>(FWD(p)) 初始化第二个元素。
- 此重载仅当以下条件全部满足时参与重载决议:
sizeof...(Types) == 2,std::is_constructible_v<T0, decltype(std::get<0>(FWD(p)))>为true,且std::is_constructible_v<T1, decltype(std::get<1>(FWD(p)))>为true。
- 当且仅当
explicit或std::is_convertible_v<decltype(std::get<0>(FWD(p))), T0>为std::is_convertible_v<decltype(std::get<1>(FWD(p))), T1>时,该构造函数为false。
|
(C++23 起) |
12)
tuple-like 构造函数。从 u 的对应元素构造 tuple 的每个元素。
正式地,对于所有 i,用 i 初始化 tuple 的第 std::get<i>(std::forward<UTuple>(u)) 个元素。
- 此重载仅当以下条件全部满足时参与重载决议:
std::same_as<std::remove_cvref_t<UTuple>, std::tuple>为false,std::remove_cvref_t<UTuple>不是 std::ranges::subrange 的特化,sizeof...(Types)等于std::tuple_size_v<std::remove_cvref_t<UTuple>>,std::is_constructible_v<Ti, decltype(std::get<i>(std::forward<UTuple>(u)))>对于所有true为i,且- 要么
sizeof...(Types)不是1,要么- (当
Types...展开为T时)std::is_convertible_v<UTuple, T>和std::is_constructible_v<T, UTuple>均为false。
- 如果任何为引用的元素的初始化会将其绑定到临时对象,则该构造函数被定义为弃置。
13) 隐式定义的拷贝构造函数。用
other 的对应元素初始化 tuple 的每个元素。
- 如果它执行的每个操作都是 constexpr,则该构造函数为 constexpr。对于空 tuple
std::tuple<>,它是 constexpr。 std::is_copy_constructible<Ti>::value必须为对于所有true的i,否则行为未定义(C++20 前)程序非良构(C++20 起)。
14) 隐式定义的移动构造函数。对于所有
i,用 i 初始化 tuple 的第 std::forward<Ui>(std::get<i>(other)) 个元素。
- 如果它执行的每个操作都是 constexpr,则该构造函数为 constexpr。对于空 tuple
std::tuple<>,它是 constexpr。 std::is_move_constructible<Ti>::value必须为对于所有true的i,否则行为未定义(C++20 前)此重载不参与重载决议(C++20 起)。
15-28) 与 (1-14) 相同,只不过每个元素都通过使用分配器构造创建,即对于
a 为 std::uses_allocator<Ui, Alloc>::value 的每个元素,将 Allocator 对象 true 作为附加参数传递给其构造函数。参数
| args | - | 用于初始化元组各元素的值 |
| other | - | 用于初始化元组各元素的值元组 |
| p | - | 用于初始化二元组两个元素的数值对 |
| u | - |
用于初始化元组各元素的
tuple-like
对象值
|
| a | - | 用于分配器构造的分配器 |
注释
条件显式构造函数使得在复制初始化上下文中使用列表初始化语法构造元组成为可能:
std::tuple<int, int> foo_tuple() { // return {1, -1}; // N4387 之前的错误用法 return std::make_tuple(1, -1); // 始终有效 }
请注意,如果列表中的某些元素无法隐式转换为目标元组的对应元素,则构造函数将变为显式:
using namespace std::chrono; void launch_rocket_at(std::tuple<hours, minutes, seconds>); launch_rocket_at({hours(1), minutes(2), seconds(3)}); // 正确 launch_rocket_at({1, 2, 3}); // 错误:int 不能隐式转换为 duration 类型 launch_rocket_at(std::tuple<hours, minutes, seconds>{1, 2, 3}); // 正确
示例
运行此代码
#include <iomanip> #include <iostream> #include <memory> #include <string> #include <string_view> #include <tuple> #include <type_traits> #include <vector> // 辅助函数,用于将向量打印到流 template<class Os, class T> Os& operator<<(Os& os, std::vector<T> const& v) { os << '{'; for (auto i{v.size()}; const T& e : v) os << e << (--i ? "," : ""); return os << '}'; } template<class T> void print_single(T const& v) { if constexpr (std::is_same_v<T, std::decay_t<std::string>>) std::cout << std::quoted(v); else if constexpr (std::is_same_v<std::decay_t<T>, char>) std::cout << "'" << v << "'"; else std::cout << v; } // 用于打印任意大小元组的辅助函数 template<class Tuple, std::size_t N> struct TuplePrinter { static void print(const Tuple& t) { TuplePrinter<Tuple, N - 1>::print(t); std::cout << ", "; print_single(std::get<N - 1>(t)); } }; template<class Tuple> struct TuplePrinter<Tuple, 1> { static void print(const Tuple& t) { print_single(std::get<0>(t)); } }; template<class... Args> void print(std::string_view message, const std::tuple<Args...>& t) { std::cout << message << " ("; TuplePrinter<decltype(t), sizeof...(Args)>::print(t); std::cout << ")\n"; } // 结束辅助函数 int main() { std::tuple<int, std::string, double> t1; print("值初始化,t1:", t1); std::tuple<int, std::string, double> t2{42, "测试", -3.14}; print("使用值初始化,t2:", t2); std::tuple<char, std::string, int> t3{t2}; print("隐式转换,t3:", t3); std::tuple<int, double> t4{std::make_pair(42, 3.14)}; print("由一对构造,t4:", t4); // 给定分配器 my_alloc 具有单参数构造函数 // my_alloc(int); 使用 my_alloc(1) 在 vector 中分配 5 个 int using my_alloc = std::allocator<int>; std::vector<int, my_alloc> v{5, 1, my_alloc{/* 1 */}}; // 使用 my_alloc(2) 在元组中的向量内分配 5 个整型 std::tuple<int, std::vector<int, my_alloc>, double> t5 {std::allocator_arg, my_alloc{/* 2 */}, 42, v, -3.14}; print("使用分配器构造,t5:", t5); }
可能的输出:
值初始化,t1: (0, "", 0)
使用值初始化,t2: (42, "Test", -3.14)
隐式转换,t3: ('*', "Test", -3)
从 pair 构造,t4: (42, 3.14)
使用分配器构造,t5: (42, {1,1,1,1,1}, -3.14)
缺陷报告
以下行为变更缺陷报告被追溯应用于先前发布的C++标准。
| 缺陷报告 | 适用版本 | 发布时行为 | 正确行为 |
|---|---|---|---|
| LWG 2510 | C++11 | 默认构造函数为隐式 | 改为条件性显式 |
| LWG 3121 | C++11 |
单元素元组构造函数可能递归检查约束;
allocator_arg_t
参数引发歧义
|
进一步约束构造函数 |
| LWG 3158 | C++11 | 对应默认构造函数的分配器使用构造函数为隐式 | 改为条件性显式 |
| LWG 3211 | C++11 |
tuple<>
的默认构造函数是否为平凡未作规定
|
要求必须为平凡 |
| LWG 4045 | C++23 |
类元组
构造函数可能产生悬垂引用
|
定义为已删除 |
| N4387 | C++11 | 部分构造函数为显式,阻碍了有用行为 | 多数构造函数改为条件性显式 |
另请参阅
将一个
tuple
的内容赋值给另一个
(公开成员函数) |
|
|
(C++11)
|
创建由参数类型定义的
tuple
对象
(函数模板) |
|
(C++11)
|
创建左值引用组成的
tuple
或将 tuple 解包为独立对象
(函数模板) |
|
(C++11)
|
创建
转发引用
组成的
tuple
(函数模板) |
构造新的
pair
(
std::pair<T1,T2>
的公开成员函数)
|