如何基于多组可变参数模板列表调用模板函数
问题描述
现有模板函数:
template <typename T, typename U, typename V, typename W> void MyFunc() { // stuff... }
需要针对给定的多组类型的所有组合调用该函数,具体类型组如下:
- T: char, int, long long
- U: float, double
- V: std::uint64_t, std::string_view
- W: int, MyEnum1, MyEnum2, MyEnum3
对应的伪代码逻辑为:
foreach (t in { char, int, long long }) { foreach (u in { float, double }) { foreach (v in { std::uint64_t, std::string_view }) { foreach (w in { int, MyEnum1, MyEnum2, MyEnum3 }) { MyFunc<t, u, v, w>(); } } } }
已知可变参数模板、元组或「类型列表」等技巧可实现该需求,但未能梳理出具体方案,请问如何实现?
实现方案
方法1:C++17+ 用std::tuple+折叠表达式实现(推荐)
利用C++17的std::apply和折叠表达式,可以简洁遍历所有类型组合,无需手写递归模板:
#include <tuple> #include <string_view> #include <cstdint> #include <type_traits> // 定义所需枚举 enum class MyEnum1 {}; enum class MyEnum2 {}; enum class MyEnum3 {}; template <typename T, typename U, typename V, typename W> void MyFunc() { // 替换为你的实际业务逻辑 } // 触发所有组合调用的入口函数 void invoke_all_combinations() { // 用std::tuple存储各类型组的类型列表 using TTypes = std::tuple<char, int, long long>; using UTypes = std::tuple<float, double>; using VTypes = std::tuple<std::uint64_t, std::string_view>; using WTypes = std::tuple<int, MyEnum1, MyEnum2, MyEnum3>; // 嵌套std::apply逐层展开每个类型组,最后用折叠表达式遍历W的所有类型 std::apply([](auto... ts) { std::apply([ts...](auto... us) { std::apply([ts..., us...](auto... vs) { std::apply([ts..., us..., vs...](auto... ws) { // 折叠表达式展开所有W类型,生成MyFunc的所有组合调用 (MyFunc<std::decay_t<decltype(ts)>, std::decay_t<decltype(us)>, std::decay_t<decltype(vs)>, std::decay_t<decltype(ws)>>(), ...); }, WTypes{}); }, VTypes{}); }, UTypes{}); }, TTypes{}); }
方法2:兼容C11/C14 自定义类型列表+递归模板
如果需要支持更早的C++标准,可通过自定义类型列表配合递归模板逐层展开:
#include <string_view> #include <cstdint> enum class MyEnum1 {}; enum class MyEnum2 {}; enum class MyEnum3 {}; template <typename T, typename U, typename V, typename W> void MyFunc() { // 替换为你的实际业务逻辑 } // 自定义类型列表结构 template <typename... Ts> struct type_list {}; // 递归展开W类型组 template <typename T, typename U, typename V, typename WList> struct call_w; // 递归终止条件:空类型列表 template <typename T, typename U, typename V> struct call_w<T, U, V, type_list<>> { static void apply() {} }; // 展开单个W类型,然后递归处理剩余W类型 template <typename T, typename U, typename V, typename W, typename... Ws> struct call_w<T, U, V, type_list<W, Ws...>> { static void apply() { MyFunc<T, U, V, W>(); call_w<T, U, V, type_list<Ws...>>::apply(); } }; // 递归展开V类型组 template <typename T, typename U, typename VList, typename WList> struct call_v; template <typename T, typename U, typename WList> struct call_v<T, U, type_list<>, WList> { static void apply() {} }; template <typename T, typename U, typename V, typename... Vs, typename WList> struct call_v<T, U, type_list<V, Vs...>, WList> { static void apply() { call_w<T, U, V, WList>::apply(); call_v<T, U, type_list<Vs...>, WList>::apply(); } }; // 递归展开U类型组 template <typename T, typename UList, typename VList, typename WList> struct call_u; template <typename T, typename VList, typename WList> struct call_u<T, type_list<>, VList, WList> { static void apply() {} }; template <typename T, typename U, typename... Us, typename VList, typename WList> struct call_u<T, type_list<U, Us...>, VList, WList> { static void apply() { call_v<T, U, VList, WList>::apply(); call_u<T, type_list<Us...>, VList, WList>::apply(); } }; // 递归展开T类型组,触发所有组合调用 template <typename TList, typename UList, typename VList, typename WList> struct call_all; template <typename UList, typename VList, typename WList> struct call_all<type_list<>, UList, VList, WList> { static void apply() {} }; template <typename T, typename... Ts, typename UList, typename VList, typename WList> struct call_all<type_list<T, Ts...>, UList, VList, WList> { static void apply() { call_u<T, UList, VList, WList>::apply(); call_all<type_list<Ts...>, UList, VList, WList>::apply(); } }; // 主调用入口 void invoke_all_combinations() { using TTypes = type_list<char, int, long long>; using UTypes = type_list<float, double>; using VTypes = type_list<std::uint64_t, std::string_view>; using WTypes = type_list<int, MyEnum1, MyEnum2, MyEnum3>; call_all<TTypes, UTypes, VTypes, WTypes>::apply(); }
关键说明
- 两种方法都会生成
3*2*2*4=48种类型组合的MyFunc实例,覆盖所有需求中的类型组合。 - 方法1依赖C17特性,代码简洁易维护,是现代C的首选方案。
- 方法2通过递归模板实现,兼容C++11及以上标准,适合旧项目场景。
内容的提问来源于stack exchange,提问作者diccy
相关产品推荐
相关产品推荐

