std::tuple
文章目录
- std::tuple
- 成员函数及非成员函数
- 模板参数
- 成员函数
- Non-member functions非成员函数
- 辅助类
- 构造函数
- 获取元祖元素值
- 元素个数
- 元素的类型
- Reference
类模板 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)(C++11) | 构造一个新的“元组”(公共成员函数) |
---|---|
operator=(C++11) | 将一个“元组”的内容分配给另一个(公共成员函数) |
swap(C++11) | 交换两个元组的内容(公共成员函数) |
Non-member functions非成员函数
make_tuple(C++11) | 创建由参数类型(函数模板)定义的类型的“元组”对象 |
---|---|
tie(C++11) | 创建左值引用的元组或将元组解包为单个对象(函数模板) |
forward_as_tuple(C++11) | 创建 forwarding references 的“元组”(函数模板) |
tuple_cat(C++11) | 通过连接任意数量的元组(函数模板)创建一个“元组” |
std::get(std::tuple)(C++11) | 元组访问指定元素(函数模板) |
operator==operator!=operatoroperator>=operator<=>(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)(C++11) | 特化 std::swap 算法(函数模板) |
辅助类
std::tuple_size(C++11) | 在编译时获得 tuple 的大小(类模板特化) |
---|---|
std::tuple_element(C++11) | 获得指定元素的类型(类模板特化) |
std::uses_allocator(C++11) | 特化 std::uses_allocator 类型特征(类模板特化) |
std::basic_common_reference<tuple-like>(C++23) | 确定“元组”和类元组类型的公共引用类型(类模板特化) |
std::common_type<tuple-like>(C++23) | 确定“元组”的通用类型和类元组类型(类模板特化) |
ignore(C++11) | 使用 tie 解压 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
Reference
- std::tuple
欢迎关注公众号【三戒纪元】