C++ 中 std::tuple
使用详解
基本概念
std::tuple
是 C++11 引入的模板类,用于打包任意数量、任意类型的值在一起。可看作是类型安全的变长结构体。
#include <tuple>std::tuple<int, std::string, double> t(42, "hello", 3.14);
创建 tuple 的方法
auto t1 = std::make_tuple(1, 2.5, "abc"); // 自动推导类型
std::tuple<int, float, const char*> t2(1, 2.5f, "abc");
std::make_tuple
会自动进行类型推导和转化。
访问元素:std::get<>
#include <iostream>std::tuple<int, std::string, double> t(1, "hi", 3.14);
std::cout << std::get<1>(t) << std::endl; // 输出 "hi"
注意:必须使用编译期常量作为索引,不能传运行时变量!
获取类型 & 大小
#include <tuple>
#include <type_traits>using MyTuple = std::tuple<int, float, std::string>;constexpr std::size_t size = std::tuple_size<MyTuple>::value;
using T1 = std::tuple_element<1, MyTuple>::type; // float
修改元素值
std::get<2>(t) = 6.28; // 修改 double 类型的值
拆解 tuple(结构化绑定)
C++17 提供结构化绑定:
auto [x, y, z] = t; // 自动展开为三个变量
tuple 的比较、赋值
std::tuple<int, int> a(1, 2), b(1, 3);
if (a < b) std::cout << "a < b"; // 支持逐元素比较
高级技巧:递归访问 tuple
遍历 tuple 中所有元素(使用模板递归)
#include <iostream>
#include <tuple>template<std::size_t I = 0, typename... Ts>
void print_tuple(const std::tuple<Ts...>& t) {if constexpr (I < sizeof...(Ts)) {std::cout << std::get<I>(t) << " ";print_tuple<I + 1>(t);}
}int main() {auto t = std::make_tuple(1, 3.14, "hello");print_tuple(t); // 输出: 1 3.14 hello
}
对每个元素执行函数(C++17 fold expression
)
template<typename... Ts>
void apply_to_each(const std::tuple<Ts...>& t) {std::apply([](const auto&... args) {((std::cout << args << " "), ...);}, t);
}
根据类型访问 tuple 元素(要求类型唯一)
template<typename T, typename... Ts>
T& get_by_type(std::tuple<Ts...>& t) {return std::get<T>(t);
}std::tuple<int, double, std::string> t{42, 3.14, "hi"};
auto& str = get_by_type<std::string>(t); // OK
⚠️ 不能有多个相同类型,否则编译失败!
与 std::tie
结合解包、忽略元素
int a; std::string b;
std::tuple<int, std::string, double> t{10, "hi", 3.14};std::tie(a, b, std::ignore) = t; // 忽略第三个元素
tuple 的拼接:std::tuple_cat
auto t1 = std::make_tuple(1, "x");
auto t2 = std::make_tuple(3.14, false);
auto t3 = std::tuple_cat(t1, t2); // 拼接 tuple
注意事项
std::get<index>(tuple)
的 index 必须是 编译时常量。- 用类型访问元素(
std::get<T>
)时类型必须唯一。 - tuple 不支持运行时下标访问(不像 vector)。
- 不适用于极大量元素(模板编译速度会极慢)。
std::apply
是处理 tuple 和函数调用结合的利器(见下节)。
函数调用 + tuple 参数展开:std::apply
#include <tuple>void func(int a, double b, const std::string& c) {std::cout << a << ", " << b << ", " << c << "\n";
}int main() {auto t = std::make_tuple(1, 3.14, "hello"s);std::apply(func, t); // 自动解包调用 func
}
实战示例:递归地对 tuple 中所有值加倍
template <std::size_t I = 0, typename... Ts>
void double_tuple(std::tuple<Ts...>& t) {if constexpr (I < sizeof...(Ts)) {std::get<I>(t) *= 2;double_tuple<I + 1>(t);}
}
适用于所有支持 *=
操作的类型。
小结
功能 | 工具 |
---|---|
构造 tuple | std::make_tuple , 构造函数 |
访问元素 | std::get<index> , std::get<T> |
获取信息 | std::tuple_size , std::tuple_element |
遍历元素 | 模板递归 / std::apply + fold |
类型安全调用 | std::apply(func, tuple) |
拼接 | std::tuple_cat |
解包 | C++17 结构化绑定、std::tie |
忽略元素 | std::ignore |