std::index_sequence 是编译期元组索引的类型级列表,本质为模板参数包包装器,用于展开可变参数模板;不可运行时操作,零开销,需传编译期常量,常见于tuple拆包、std::apply等场景。

std::index_sequence 是什么,为什么不能用 vector 替代
它不是运行时容器,而是编译期元组索引的“类型级列表”——本质是模板参数包的包装器,用于展开可变参数模板。你没法对它 push_back、size() 或遍历,它只在模板实例化时起作用。
- 常见错误现象:
error: no matching function for call to 'make_index_sequence',通常是因为传了非字面量整数(比如变量n而非5) - 使用场景:完美转发参数包、结构体绑定(
std::tie)、tuple 拆包、实现std::apply - 性能影响:零开销——所有信息在编译期消化,生成的汇编里完全不出现
index_sequence相关痕迹
怎么生成指定长度的 index_sequence
直接用标准提供的别名模板,但必须传编译期常量。
-
std::make_index_sequence<n></n>→ 得到std::index_sequence,N必须是常量表达式 -
std::index_sequence_for<ts...></ts...>→ 根据类型包长度推导,比如index_sequence_for<int char void></int>展开为index_sequence - 容易踩的坑:写
int n = 3; make_index_sequence<n></n>会编译失败;得用constexpr int n = 3;或直接写死数字
怎么在函数模板里用 index_sequence 拆包参数包
核心是把 index_sequence 当作“展开钥匙”,让编译器把参数包按序号映射过去。
- 典型模式:定义一个带
index_sequence参数的私有辅助函数,再用make_index_sequence触发推导 - 示例:把 tuple 打印出来
template <class Tuple, std::size_t... I>
void print_tuple_impl(const Tuple& t, std::index_sequence<I...>) {
((std::cout << std::get<I>(t) << " "), ...); // C++17 折叠表达式
}
template <class... Ts>
void print_tuple(const std::tuple<Ts...>& t) {
print_tuple_impl(t, std::make_index_sequence<sizeof...(Ts)>{});
}
- 关键点:
I...在调用时被展开为0,1,2等,从而让std::get<i>(t)</i>逐个生效 - 兼容性注意:C++14 支持
make_index_sequence,但折叠表达式要 C++17;C++14 得用递归或逗号表达式模拟
自定义 index_sequence 的边界情况
标准库没提供 make_index_sequence_from 这种东西,想从 1 开始或倒序?得自己造。
立即学习“C++免费学习笔记(深入)”;
- 常见需求:生成
index_sequence(跳过 0)→ 可用std::make_index_sequence+ 偏移:定义offset_sequence<offset seq></offset>模板偏特化 - 错误示范:试图用
std::integer_sequence<int></int>替代 —— 它和index_sequence不同源,很多标准算法(如make_from_tuple)只认后者 - 容易被忽略的点:
std::index_sequence底层是std::integer_sequence<:size_t ...></:size_t>的别名,所以序列里的值类型固定为std::size_t,不能是int或long










