如何遍历类型名列表的所有组合并调用模板函数?
遍历类型列表的所有组合并处理
要实现编译期遍历类型列表的所有笛卡尔积组合,核心是利用编译期整数序列展开——因为运行期循环变量无法作为模板参数传递。下面提供几种可行方案:
方案1:递归展开(C++11及以上)
通过递归逐个处理每个外层类型,再递归处理内层的每个类型,覆盖所有组合:
#include <iostream> #include <limits> #include <tuple> #include <cstdint> template<typename T, typename R> void foo() { std::cout << std::numeric_limits<T>::max() << ", " << std::numeric_limits<R>::max() << '\n'; } // 处理单个外层类型T与所有内层类型 template<typename T, typename Tuple, size_t... Js> void process_inner(std::index_sequence<Js...>) { (foo<T, std::tuple_element_t<Js, Tuple>>(), ...); // C++17折叠表达式,简化展开逻辑 } // 遍历所有外层类型 template<typename Tuple, size_t... Is> void process_outer(std::index_sequence<Is...>) { (process_inner<std::tuple_element_t<Is, Tuple>, Tuple>(std::make_index_sequence<std::tuple_size_v<Tuple>>()), ...); } void call() { using int_types = std::tuple<int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t>; process_outer<int_types>(std::make_index_sequence<std::tuple_size_v<int_types>>()); } int main() { call(); return 0; }
如果是C++11(不支持折叠表达式),可以把内层展开改成递归模板:
// C++11版本内层递归辅助模板 template<typename T, typename Tuple, size_t J> struct inner_helper { static void call() { foo<T, std::tuple_element_t<J-1, Tuple>>(); inner_helper<T, Tuple, J-1>::call(); } }; template<typename T, typename Tuple> struct inner_helper<T, Tuple, 0> { static void call() {} }; template<typename T, typename Tuple> void process_inner_cpp11() { inner_helper<T, Tuple, std::tuple_size<Tuple>::value>::call(); } // 外层递归同理修改即可
方案2:C++20模板lambda简化写法
利用C++20的模板lambda,省去额外的递归函数,代码更紧凑:
#include <iostream> #include <limits> #include <tuple> #include <cstdint> #include <utility> template<typename T, typename R> void foo() { std::cout << std::numeric_limits<T>::max() << ", " << std::numeric_limits<R>::max() << '\n'; } void call() { using int_types = std::tuple<int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t>; constexpr auto size = std::tuple_size_v<int_types>; // 展开外层索引 [&]<size_t... Is>(std::index_sequence<Is...>) { ( // 展开内层索引 [&]<size_t... Js>(std::index_sequence<Js...>) { (foo<std::tuple_element_t<Is, int_types>, std::tuple_element_t<Js, int_types>>(), ...); }(std::make_index_sequence<size>()), ... ); }(std::make_index_sequence<size>()); } int main() { call(); return 0; }
核心原理说明
std::index_sequence和std::make_index_sequence生成编译期整数序列,序列中的每个值都是编译期常量,可安全作为std::tuple_element_t的模板参数。- 折叠表达式(C++17+)替代递归模板,大幅简化展开逻辑。
- 模板lambda(C++20+)允许在lambda内部使用模板参数,无需额外定义辅助函数或模板,代码结构更简洁。
内容的提问来源于stack exchange,提问作者Robin
相关产品推荐
相关产品推荐

