如何使用折叠表达式展开parameter pack并传递每个元素的对应索引
实现方案
该需求完全可以通过C++17引入的折叠表达式实现,核心思路是结合编译期索引序列std::index_sequence和逗号折叠表达式完成参数包展开,以下是可运行的实现:
C++20 最简写法(支持模板lambda)
#include <utility> // 用于std::index_sequence、std::forward等工具 // 你提供的目标函数 struct Record {}; // 补全Record类型方便编译 template<typename T> void addToRecord(Record& rec, int idx, T&& val) { // Do some stuff. } template<typename... ARGS> void addRecord(ARGS&& ...values) { Record rec; // 生成索引序列+折叠表达式展开调用 [&]<std::size_t... Is>(std::index_sequence<Is...>, auto&& vals) { // 逗号折叠表达式,按顺序执行每个addToRecord调用 (addToRecord(rec, static_cast<int>(Is), std::get<Is>(vals)), ...); }( std::make_index_sequence<sizeof...(ARGS)>{}, std::forward_as_tuple(std::forward<ARGS>(values)...) ); // 后续处理rec的逻辑 }
C++17 兼容写法(无模板lambda)
如果需要兼容C++17标准,可以将lambda的逻辑抽为独立的辅助模板函数:
#include <utility> struct Record {}; template<typename T> void addToRecord(Record& rec, int idx, T&& val) { // Do some stuff. } // 辅助展开函数 template<typename Tuple, std::size_t... Is> void batchAddToRecord(Record& rec, Tuple&& vals, std::index_sequence<Is...>) { (addToRecord(rec, static_cast<int>(Is), std::get<Is>(std::forward<Tuple>(vals))), ...); } template<typename... ARGS> void addRecord(ARGS&& ...values) { Record rec; batchAddToRecord( rec, std::forward_as_tuple(std::forward<ARGS>(values)...), std::make_index_sequence<sizeof...(ARGS)>{} ); // 后续处理rec的逻辑 }
原理解释
- 首先通过
std::make_index_sequence<sizeof...(ARGS)>生成和参数包长度完全一致的编译期整数序列0,1,2,...,N-1,每个整数对应该位置参数的索引 - 用
std::forward_as_tuple将参数包打包为元组,保留所有参数的左右值属性,方便按索引取值 - 这里使用的是一元右逗号折叠,展开后会按顺序执行每个索引对应的
addToRecord调用,执行顺序和参数包的传入顺序完全一致,和递归实现的效果完全相同。
如果你的参数包长度可能超过int的最大值,建议将addToRecord的idx参数类型改为std::size_t,避免类型转换的溢出风险。
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

