类模板 std::tuple 是不同类型值的固定大小集合。 它是 std::pair 的泛化。 可以当做一个结构体使用 ,不需要创建结构体就能获得结构体的特征
std::tuple理论上可以有无数个任意类型的成员变量,而std::pair只能是2个成员,因此在需要保存3个及以上的数据时就需要使用tuple元组了
直观感受一下:
#include < iostream >
#include < tuple >
int main(int argc, char **argv) {
typedef std::tuple< int, double, int, double > Randy;
Randy q0(0, 1, 2, 3);
// display contents " 0 1 2 3"
std::cout < < " " < < std::get< 0 >(q0);
std::cout < < " " < < std::get< 1 >(q0);
std::cout < < " " < < std::get< 2 >(q0);
std::cout < < " " < < std::get< 3 >(q0);
std::cout < < std::endl;
Randy q1;
q1 = q0;
// display contents " 0 1 2 3"
std::cout < < " " < < std::get< 0 >(q1);
std::cout < < " " < < std::get< 1 >(q1);
std::cout < < " " < < std::get< 2 >(q1);
std::cout < < " " < < std::get< 3 >(q1);
std::cout < < std::endl;
std::tuple< char, int > q2(std::make_pair('x', 4));
// display contents " x 4"
std::cout < < " " < < std::get< 0 >(q2);
std::cout < < " " < < std::get< 1 >(q2);
std::cout < < std::endl;
Randy q3(q0);
// display contents " 0 1 2 3"
std::cout < < " " < < std::get< 0 >(q3);
std::cout < < " " < < std::get< 1 >(q3);
std::cout < < " " < < std::get< 2 >(q3);
std::cout < < " " < < std::get< 3 >(q3);
std::cout < < std::endl;
typedef std::tuple< int, float, int, float > Randy2;
Randy q4(Randy2(4, 5, 6, 7));
// display contents " 4 5 6 7"
std::cout < < " " < < std::get< 0 >(q4);
std::cout < < " " < < std::get< 1 >(q4);
std::cout < < " " < < std::get< 2 >(q4);
std::cout < < " " < < std::get< 3 >(q4);
std::cout < < std::endl;
return (0);
}
result:
0 1 2 3
0 1 2 3
x 4
0 1 2 3
4 5 6 7
成员函数及非成员函数
模板参数
Types... | -元组存储的元素的类型。 支持空列表。 | |
---|---|---|
成员函数
(constructor) ^[1]^ (C++11) | 构造一个新的“元组”(公共成员函数) |
---|---|
operator= ^[2]^ (C++11) | 将一个“元组”的内容分配给另一个(公共成员函数) |
swap ^[3]^ (C++11) | 交换两个元组的内容(公共成员函数) |
Non-member functions非成员函数
make_tuple ^[4]^ (C++11) | 创建由参数类型(函数模板)定义的类型的“元组”对象 |
---|---|
tie ^[5]^ (C++11) | 创建左值引用的元组或将元组解包为单个对象(函数模板) |
forward_as_tuple ^[6]^ (C++11) | 创建 forwarding references^[7]^ 的“元组”(函数模板) |
tuple_cat ^[8]^ (C++11) | 通过连接任意数量的元组(函数模板)创建一个“元组” |
std::get(std::tuple) ^[9]^ (C++11) | 元组访问指定元素(函数模板) |
operator==operator!=operatoroperator>=operator<=> ^[10]^ (removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(C++20) | 按字典顺序比较元组中的值(函数模板) |
std::swap(std::tuple) ^[11]^ (C++11) | 特化 std::swap^[12]^ 算法(函数模板) |
辅助类
std::tuple_size ^[13]^ (C++11) | 在编译时获得tuple 的大小(类模板特化) |
---|---|
std::tuple_element ^[14]^ (C++11) | 获得指定元素的类型(类模板特化) |
std::uses_allocator ^[15]^ (C++11) | 特化 std::uses_allocator^[16]^ 类型特征(类模板特化) |
std::basic_common_reference< tuple-like > ^[17]^ (C++23) | 确定“元组”和类元组类型的公共引用类型(类模板特化) |
std::common_type< tuple-like > ^[18]^ (C++23) | 确定“元组”的通用类型和类元组类型(类模板特化) |
ignore ^[19]^ (C++11) | 使用tie ^[20]^ 解压tuple 时跳过元素的占位符(常量) |
构造函数
#include < iomanip >
#include < iostream >
#include < memory >
#include < string >
#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(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, t1: ";
print(t1);
std::tuple< int, std::string, double > t2{42, "Test", -3.14};
std::cout < < "Initialized with values, t2: ";
print(t2);
std::tuple< char, std::string, int > t3{t2};
std::cout < < "Implicitly converted, t3: ";
print(t3);
std::tuple< int, double > t4{std::make_pair(42, 3.14)};
std::cout < < "Constructed from a pair, t4: ";
print(t4);
// 给定的分配器 my_alloc 具有单参数构造函数
// my_alloc(int); 使用 my_alloc(1) 在向量中分配 5 个整数
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};
std::cout < < "Constructed with allocator, t5: ";
print(t5);
}
结果:
Value-initialized, t1: (0, "", 0)
Initialized with values, t2: (42, "Test", -3.14)
Implicitly converted, t3: ('*', "Test", -3)
Constructed from a pair, t4: (42, 3.14)
Constructed with allocator, t5: (42, {1,1,1,1,1}, -3.14)
获取元祖元素值
#include < tuple >
#include < iostream >
#include < string >
#include < stdexcept >
std::tuple< double, char, std::string > get_student(int id)
{
switch (id)
{
case 0: return {2.13, 'A', "Randy Simpson"};
case 1: return {2.9, 'C', "Milhouse Sesame"};
case 2: return {1.22, 'D', "Kim Wiggum"};
case 3: return {0.6, 'F', "SanJie JiYuan"};
}
throw std::invalid_argument("id");
}
int main()
{
const auto student0 = get_student(0);
std::cout < < "ID: 0, "
< < "GPA: " < < std::get< 0 >(student0) < < ", "
< < "grade: " < < std::get< 1 >(student0) < < ", "
< < "name: " < < std::get< 2 >(student0) < < 'n';
const auto student1 = get_student(1);
std::cout < < "ID: 1, "
< < "GPA: " < < std::get< double >(student1) < < ", "
< < "grade: " < < std::get< char >(student1) < < ", "
< < "name: " < < std::get< std::string >(student1) < < 'n';
double gpa2;
char grade2;
std::string name2;
std::tie(gpa2, grade2, name2) = get_student(2);
std::cout < < "ID: 2, "
< < "GPA: " < < gpa2 < < ", "
< < "grade: " < < grade2 < < ", "
< < "name: " < < name2 < < 'n';
// C++17 structured binding:
const auto [ gpa3, grade3, name3 ] = get_student(3);
std::cout < < "ID: 3, "
< < "GPA: " < < gpa3 < < ", "
< < "grade: " < < grade3 < < ", "
< < "name: " < < name3 < < 'n';
}
结果:
ID: 0, GPA: 2.13, grade: A, name: Randy Simpson
ID: 1, GPA: 2.9, grade: C, name: Milhouse Sesame
ID: 2, GPA: 1.22, grade: D, name: Kim Wiggum
ID: 3, GPA: 0.6, grade: F, name: SanJie JiYuan
元素个数
std::tuple< int, char, double > randy (2, 'san_jie_ji_yuan', 0.13);
std::cout < < std::tuple_size< decltype(randy) >::value;
结果: 3
元素的类型
std::tuple< std::string, int > tq("Randy", 213);
std::tuple_element< 1, decltype(tq) >::type sesames;
sesames = std::get< 1 >(tq);
std::cout < < "sesames: " < < sesames < < std::endl;
结果:sesames: 213
评论
查看更多