【C++ 11 模板类】tuple 元组
文章目录
- 【 1. 基础概念 】
- 与 `pair` 和 `struct` 的对比
- 【 2. tuple 的创建 】
- 2.1 构造函数的方式创建
- 2.2 使用花括号初始化
- 2.3 使用 `std::make_tuple`
- 2.4 使用 `std::tie`(用于解包,但也可用于初始化空 tuple)
- 2.5 `empty_tuple` 创建空 tuple
- 2.6 从 tuple 创建另一个 tuple(类型转换)
- 【 3. 访问 tuple 元素 】
- 3.1 使用 `std::get<index>(tuple)`
- 3.2 结构化绑定(C++17,强烈推荐)
- 【 4. tuple 的操作 】
- 4.1 获取 tuple 大小 `tuple_size_v<decltype(t)>`
- 4.2 获取特定位置的类型
- 4.3 比较操作
- 4.4 拼接 tuple `std::tuple_cat`
- 4.5 遍历 tuple
- 【 5. 应用场景 】
- 5.1 函数返回多个值
- 5.2 作为容器的键
【 1. 基础概念 】
std::tuple
在 C++11 引入,用于将不同类型的数据组合成一个单一的对象。它类似于 std::pair
,但可以包含任意数量的元素(包括零个)。
- 定义:
std::tuple
是一个模板类,可以存储固定数量的、不同类型的数据元素。 - 头文件:
#include <tuple>
- 命名空间:
std
- 编译时确定大小:tuple 的大小(即包含的元素个数)在编译时就已经完全确定,并且不可改变。它不是动态容器。
与 pair
和 struct
的对比
特性 | std::tuple | std::pair | struct |
---|---|---|---|
元素数量 | 任意 | 2 | 任意 |
元素命名 | 无(通过索引) | first, second | 自定义 |
可读性 | 低 | 中 | 高 |
灵活性 | 高 | 低 | 中 |
适用场景 | 临时组合、泛型 | 键值对 | 有明确语义的数据 |
【 2. tuple 的创建 】
2.1 构造函数的方式创建
tuple<int, string, double> t1(10, "Zhen", 95.5);
2.2 使用花括号初始化
tuple<int, string> t2{42, "Sheng"};
tuple<int, string> t3 = {42, "Wo"};
tuple<int, double> t4{}; // 所有成员被默认初始化
tuple<int, double> t5 = {}; // 所有成员被默认初始化
2.3 使用 std::make_tuple
auto t4 = make_tuple(20, "Ai", 88.0);
// 类型自动推导,推荐使用
2.4 使用 std::tie
(用于解包,但也可用于初始化空 tuple)
int a;
string b ;
double c;
auto t3 = tie(a, b, c); // 创建引用 tuple
2.5 empty_tuple
创建空 tuple
tuple<> empty_tuple;
2.6 从 tuple 创建另一个 tuple(类型转换)
auto t1 = make_tuple(1, 2.5);
auto t2 = make_tuple<long, float>(t1); // 类型转换
【 3. 访问 tuple 元素 】
3.1 使用 std::get<index>(tuple)
- 通过索引访问元素(索引从 0 开始)
#include <iostream>
#include <tuple>
#include <string>
using namespace std;
int main() {tuple <int,float,string>(1314, 0.521, "Ni");// 通过索引访问元素(索引从 0 开始)cout << "Index 0: " << get<0>(t) << "\n";cout << "Index 1: " << get<1>(t) << "\n";cout << "Index 2: " << get<2>(t) << "\n";return 0;
}
- 注意: 索引 inde 必须是编译时常量,不能是变量 。
#include <iostream>
#include <tuple>
#include <string>
using namespace std;
int main() {tuple <int,float,string> t(1314, 0.521, "Ni");int index = 0;// 报错:get<>() 的 <> 中必须是常量cout << "Index 0: " << get<index>(t) << "\n";//正确cout << "Index 0: " << get<0>(t) << "\n";return 0;
}
std::get
也可以用于修改元素:
tuple <int,float,string> t(1314, 0.521, "Ni");
get<2>(t) = "new";
3.2 结构化绑定(C++17,强烈推荐)
- 这是访问 tuple 最优雅的方式:
#include <iostream>
#include <tuple>
#include <string>
using namespace std;
int main() {auto t = make_tuple(42, 3.14, string("Modern C++"));// 结构化绑定:将 tuple 解包为独立变量auto [id, value, name] = t; // 这行代码的含义是:“把这个 tuple 类型的变量 t 的第一个元素绑定到名为 id 的变量,第二个绑定到 value,第三个绑定到 name。”cout << "ID: " << id << ", Value: " << value << ", Name: " << name << "\n";// 也可以声明为引用以修改原 tupleauto& [ref_id, ref_value, ref_name] = t;ref_id = 99;cout << "Modified ID: " << get<0>(t) << "\n"; // 99return 0;
}
【 4. tuple 的操作 】
4.1 获取 tuple 大小 tuple_size_v<decltype(t)>
tuple_size_v<decltype(t)>
auto t = std::make_tuple(1, 2.5, "hello", true);
constexpr size_t size = tuple_size_v<decltype(t)>; // C++17// 输出为 3
4.2 获取特定位置的类型
auto t = std::make_tuple(1, 2.5, "hello", true);
using ThirdType = tuple_element_t<2, decltype(t)>;
// ThirdType 是 std::string
4.3 比较操作
tuple
支持完整的比较操作(==
,!=
,<
,<=
,>
,>=
),按字典序比较:- tuple 内的元素依次比较,直到比较出结果
#include <iostream>
#include <tuple>
#include <string>
using namespace std;
int main() {auto t1 = make_tuple(1, "apple");auto t2 = make_tuple(1, "banana");auto t3 = make_tuple(2, "apple");cout << (t1 < t2) << "\n"; // 1cout << (t1 < t3) << "\n"; // 1cout << (t2 < t3) << "\n"; // 1return 0;
}
4.4 拼接 tuple std::tuple_cat
#include <iostream>
#include <tuple>
#include <string>
using namespace std;
int main() {auto t1 = make_tuple(1, 2);auto t2 = make_tuple(3.14, "pi");auto t3 = make_tuple(true);// 拼接多个 tupleauto combined = tuple_cat(t1, t2, t3);// combined 类型: tuple<int, int, double, const char*, bool>cout << "Combined size: " << tuple_size_v<decltype(combined)> << "\n";return 0;
}
4.5 遍历 tuple
// C++17 示例:打印 tuple 所有元素
template<typename Tuple, std::size_t... I>
void print_tuple_impl(const Tuple& t, std::index_sequence<I...>) {((std::cout << (I == 0 ? "" : ", ") << std::get<I>(t)), ...);std::cout << "\n";
}template<typename... Args>
void print_tuple(const std::tuple<Args...>& t) {print_tuple_impl(t, std::index_sequence_for<Args...>{});
}// 使用
auto t = std::make_tuple(1, 2.5, "hello");
print_tuple(t); // 输出: 1, 2.5, hello
【 5. 应用场景 】
5.1 函数返回多个值
#include <tuple>
#include <iostream>
using namespace std;tuple<int, int, double> divide_with_remainder(int a, int b) {return make_tuple(a / b, a % b, static_cast<double>(a) / b);
}int main() {auto [quotient, remainder, decimal] = divide_with_remainder(10, 3);cout << "Quotient: " << quotient << ", Remainder: " << remainder << ", Decimal: " << decimal << "\n";return 0;
}
5.2 作为容器的键
map<tuple<int, string>, double> student_grades;
student_grades[{1, "Math"}] = 95.5;
student_grades[{1, "English"}] = 87.0;