如何交错展开C++模板参数包?扩展API调用方式
问题与解决方案
问题概述
现有C++模板函数somefunc,接受int、bool及其他自动推导类型的模板参数:
template <int N, bool B, auto... Args> void somefunc() { // 业务逻辑 }
支持如下调用:
somefunc<1, true, 2, false>();
需要扩展API,允许用户通过Pack结构体作为模板参数调用,要求展开后参数顺序与原有调用一致:
somefunc<Pack<1, true>, Pack<2, false>>(); // 等价于 somefunc<1, true, 2, false>()
其中Pack定义为:
template <int N, bool B> struct Pack { static constexpr int value = N; static constexpr bool flag = B; };
直接展开所有Pack::value再展开Pack::flag会导致参数顺序错误(1,2,true,false),需要实现交替展开每个Pack的value和flag。
解决方案
方法1:递归模板展开(兼容C++11及以上)
这是最简洁且兼容性最好的方案,通过递归逐个展开每个Pack的参数:
// 原模板函数保持不变 template <int N, bool B, auto... Args> void somefunc() { // 业务逻辑 } // 递归终止函数:将展开后的参数传递给原模板 template <auto... UnpackedArgs> void unpack_and_call() { somefunc<UnpackedArgs...>(); } // 递归展开单个Pack,再处理剩余Pack template <typename Pack, typename... RestPacks> void unpack_and_call() { unpack_and_call<Pack::value, Pack::flag, RestPacks...>(); } // 重载somefunc,接受Pack类型参数 template <typename... Packs> void somefunc() { unpack_and_call<Packs...>(); }
方法2:C++17折叠表达式+整数序列(现代写法)
利用C++17的折叠表达式和std::integer_sequence实现批量展开:
#include <utility> // 原模板函数保持不变 template <int N, bool B, auto... Args> void somefunc() { // 业务逻辑 } // 辅助结构体:将单个Pack转为包含value和flag的整数序列 template <typename Pack> struct PackSequence { using type = std::integer_sequence<int, Pack::value, Pack::flag>; }; template <typename Pack> using PackSequence_t = typename PackSequence<Pack>::type; // 重载版本 template <typename... Packs> void somefunc() { // 拼接所有Pack对应的序列,再展开为参数 []<int... Ts>(std::integer_sequence<int, Ts...>) { somefunc<Ts...>(); }(std::integer_sequence_cat(PackSequence_t<Packs>{}...)); }
验证调用
两种方案都支持以下两种调用方式,且效果完全一致:
// 原有调用方式 somefunc<1, true, 2, false>(); // 新扩展的调用方式 somefunc<Pack<1, true>, Pack<2, false>>();
内容的提问来源于stack exchange,提问作者lobelk
相关产品推荐
相关产品推荐

