如何通过元编程生成参数包?能否实现重复类型注入函数模板
实现重复类型参数包注入的解决方案
这个需求完全可行,我们可以通过模板元编程实现一个生成重复k次指定类型的类型列表结构体,再通过辅助模板展开这个列表,最终达到无需修改bar定义即可注入重复类型参数包的目的,且全程无需借助std::tuple。
1. 核心实现代码
定义类型列表与递归生成模板
// 类型列表模板,用于存储一组类型 template<typename... Ts> struct TypeList {}; // 递归累积重复类型的实现 template<typename T, size_t N, typename... Accum> struct GimmePackImpl { // 每次递归向累积列表中添加一个T using type = typename GimmePackImpl<T, N-1, T, Accum...>::type; }; // 递归终止条件:N减至0时返回累积的类型列表 template<typename T, typename... Accum> struct GimmePackImpl<T, 0, Accum...> { using type = TypeList<Accum...>; }; // 对外暴露的GimmePack结构体 template<typename T, size_t N> struct GimmePack { static_assert(N > 0, "GimmePack requires N to be a positive integer"); using type = typename GimmePackImpl<T, N>::type; };
定义辅助调用模板
由于C++语法限制无法直接将类型包作为单个类型别名传入模板参数,我们需要辅助模板展开TypeList中的类型:
// 辅助模板:展开TypeList并调用bar template<typename T, typename TL> struct BarInvoker; // 特化版本:匹配TypeList并展开其中的类型包 template<typename T, typename... Types> struct BarInvoker<T, TypeList<Types...>> { template<typename... Args> static void invoke(Args&&... args) { bar<T, Types...>(std::forward<Args>(args)...); } };
2. 使用方式
按照需求调用时,只需:
// 等价于直接调用bar<char, double, double, double>(x,y,z,42,dx,dy,dz,3.14159,'c') BarInvoker<char, GimmePack<double,3>::type>::invoke(x,y,z,42,dx,dy,dz,3.14159,'c');
3. 原理说明
GimmePack<T, N>通过递归模板生成包含N个T的TypeList,例如GimmePack<double,3>::type对应TypeList<double, double, double>。BarInvoker的特化版本会匹配TypeList<Types...>,将Types...展开作为bar的Types参数包,最终调用目标函数。
4. C++17简化实现(可选)
如果使用C++17,可以利用std::index_sequence和折叠表达式简化GimmePack的实现,避免递归:
#include <utility> template<typename T, size_t N> struct GimmePack { // 利用索引序列生成N个T的类型列表 template<size_t... Is> static auto make_type_list(std::index_sequence<Is...>) -> TypeList<decltype((void)Is, T)...>; using type = decltype(make_type_list(std::make_index_sequence<N>())); };
内容的提问来源于stack exchange,提问作者mhawth36
相关产品推荐
相关产品推荐

