C++17如何实现带编译时索引的可变参数包大小遍历
解决方案
编译错误的核心原因是普通for循环的循环变量是运行时值,无法作为模板参数传入std::get,C++17标准可以通过std::index_sequence生成编译期索引序列,配合折叠表达式实现参数包遍历,修改后的可编译代码如下:
可直接运行的C++17兼容实现
首先实现一个辅助模板函数完成tuple填充:
// 辅助模板:利用编译期索引序列填充tuple template <typename Tuple, typename Message, std::size_t... Is> void fillTuple(Tuple& args, const Message& message, std::index_sequence<Is...>) { // 折叠表达式展开每个索引位置的赋值操作 ((std::get<Is>(args) = message.template getArg<std::tuple_element_t<Is, Tuple>>(Is)), ...); } template <typename ...Args> void addCallback(void* handle, std::string address, std::function<void(Args...)> callback) { return addMessageCallback(std::move(address), [callback](const ci::osc::Message& message) { std::tuple<Args...> args; // 传入长度等于参数包大小的索引序列完成填充 fillTuple(args, message, std::make_index_sequence<sizeof...(Args)>{}); std::apply(callback, std::move(args)); }); }
实现说明
std::make_index_sequence<sizeof...(Args)>会在编译期生成一个从0到sizeof...(Args)-1的整数序列,所有值都是编译期常量,满足模板参数的常量要求。- 折叠表达式
((操作), ...)会依次展开每个索引对应的赋值逻辑,完全等价于你原来写的for循环,且没有任何运行时开销。 - 代码补充了
template关键字标记getArg为模板方法,避免依赖类型场景下编译器语法解析错误,同时修正了原代码中getArg调用缺少右括号的语法问题。
如果你的编译器支持C++20,还可以用模板lambda省略单独的辅助函数,代码会更简洁。
内容的提问来源于stack exchange,提问作者Tim MB
相关产品推荐
相关产品推荐

