tuple
std::tuple 是 C++11 引入的固定大小异构容器,用于将多个不同类型的值组合成一个对象。它可以容纳任意数量、任意类型的元素,是 std::pair 的扩展。
与 std::pair 的区别:
pair只能存两个元素,tuple可以存任意数量(通过模板参数)。tuple适合返回多个值的函数、多值关联等场景。- 访问方式既可以通过索引(编译时
std::get<N>),也可以通过类型(仅当该类型唯一时)。
头文件与基本特征
#include <tuple>
主要特征:
| 特征 | 说明 |
|---|---|
| 元素类型 | 任意类型(异构) |
| 大小 | 固定,编译时确定 |
| 存储方式 | 值语义(非引用) |
| 拷贝语义 | 完整拷贝 |
| 移动语义 | 支持移动构造和移动赋值 |
基本用法
使用 std::make_tuple 创建:
#include <iostream>
#include <tuple>
#include <string>
int main() {
auto t = std::make_tuple(42, std::string("hello"), 3.14);
std::cout << std::get<0>(t) << '\n'; // 42
std::cout << std::get<1>(t) << '\n'; // hello
std::cout << std::get<2>(t) << '\n'; // 3.14
return 0;
}
也可以通过构造函数直接创建:
std::tuple<int, std::string, double> t(10, "world", 2.718);
交互演示(MDX + React)
下面这个面板用于演示 make_tuple、std::get<N>、std::get<T>、std::tie 以及 std::tuple_cat 的典型行为:
std::tuple 操作演示
通过交互操作体验 tuple 的创建、元素访问、tuple_cat 等核心用法。
#0int42
#1stringhello
#2double3.14
最近操作
- 初始化: std::tuple<int, string, double>
元素访问
std::get<N>
通过编译时索引访问元素:
#include <tuple>
int main() {
auto t = std::make_tuple(100, 200, 300);
int a = std::get<0>(t); // 100
int b = std::get<1>(t); // 200
int c = std::get<2>(t); // 300
return 0;
}
索引必须是编译时常量,越界会导致编译错误。
std::get<T>
当 tuple 中某类型唯一时,可以按类型访问:
#include <tuple>
#include <string>
int main() {
auto t = std::make_tuple(42, std::string("hi"));
int n = std::get<int>(t); // 正确:int 是唯一的
std::string s = std::get<std::string>(t); // 正确:string 是唯一的
return 0;
}
如果有多个相同类型,编译会报错。
std::tie
std::tie 用于解包 tuple 到变量:
#include <tuple>
#include <string>
#include <iostream>
int main() {
auto t = std::make_tuple(1, 2, std::string("hello"));
int a, b;
std::string c;
std::tie(a, b, c) = t;
std::cout << a << ' ' << b << ' ' << c << '\n';
return 0;
}
常用场景:函数返回多个值并赋值给独立变量。
创建与赋值
std::make_tuple
自动推断元素类型:
auto t = std::make_tuple(10, 3.14, std::string("test"));
std::tuple_cat
合并多个 tuple:
#include <tuple>
#include <iostream>
int main() {
auto t1 = std::make_tuple(1, 2);
auto t2 = std::make_tuple(3, 4.0);
auto combined = std::tuple_cat(t1, t2);
// combined 是 std::tuple<int, int, int, double>
return 0;
}
pair 与 tuple 互相转换
pair 本身就是一种特殊的 tuple,可以直接赋值:
#include <tuple>
#include <utility>
#include <iostream>
int main() {
std::pair<int, std::string> p(42, "hi");
std::tuple<int, std::string> t = p;
std::pair<int, std::string> p2 = t;
return 0;
}
常用辅助函数
| 函数 | 作用 |
|---|---|
std::make_tuple() | 创建 tuple,自动推断类型 |
std::get<N>(t) | 按索引访问元素 |
std::get<T>(t) | 按类型访问元素(类型需唯一) |
std::tie() | 解包 tuple 到变量 |
std::tuple_cat() | 拼接多个 tuple |
std::tuple_size<...> | 编译时获取元素个数 |
std::tuple_element<N, ...> | 获取第 N 个元素的类型 |
operator== / operator< 等 | 逐元素比较(C++20 起支持相等比较) |
std::swap(t1, t2) | 交换两个 tuple |
tuple_size 与 tuple_element
#include <tuple>
#include <iostream>
int main() {
using T = std::tuple<int, double, std::string>;
constexpr std::size_t sz = std::tuple_size<T>::value; // 3
using FirstType = std::tuple_element_t<0, T>; // int
return 0;
}
tuple 作为函数返回值
tuple 适合从函数返回多个不同类型的值:
#include <tuple>
#include <string>
std::tuple<int, double, std::string> getRecord() {
return {42, 3.14, std::string("data")};
}
int main() {
auto [id, score, name] = getRecord(); // C++17 结构化绑定
return 0;
}
C++17 的结构化绑定让 tuple 的使用更加自然:
auto [a, b, c] = std::make_tuple(1, 2.5, std::string("x"));
常见用法示例
多值返回
#include <tuple>
#include <string>
std::tuple<bool, int, std::string> tryParse(const std::string& s) {
// 模拟解析逻辑
try {
int value = std::stoi(s);
return {true, value, ""};
} catch (...) {
return {false, 0, "parse error"};
}
}
int main() {
auto [ok, val, err] = tryParse("123");
return 0;
}
字典与多值映射
#include <tuple>
#include <unordered_map>
#include <string>
int main() {
std::unordered_map<std::string, std::tuple<int, double, std::string>> db;
db["alice"] = std::make_tuple(95, 1.65, "Beijing");
db["bob"] = std::make_tuple(88, 1.80, "Shanghai");
auto& [score, height, city] = db["alice"];
return 0;
}
使用注意
std::get<N>的索引必须是编译时常量。std::get<T>要求该类型在 tuple 中唯一。- tuple 本身不提供运行时动态添加/删除元素的能力,大小在编译时固定。
- 元素按值存储,深拷贝适用于所有非指针成员。
- 大量异构元素时,考虑是否有更清晰的专用结构体替代。
- C++17 结构化绑定
auto [a, b, c] = t;是最推荐的解包方式。
小结
std::tuple 是 C++11 处理异构数据集合的核心工具。它弥补了 std::pair 只支持两个元素的限制,配合 std::get<N>、std::tie、std::tuple_cat 等工具以及 C++17 结构化绑定,可以优雅地解决多值返回、批量数据传输等常见场景。合理使用 tuple 让代码更简洁,同时注意不要滥用导致类型混乱。