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 |