如何对type list与value list进行成对迭代?
问题:如何将type_list与值列表打包为类型/值对并进行折叠操作?
用户定义了如下type_list模板结构体:
template <typename ...Types> struct type_list {};
希望在如下函数中实现对该类型列表与某值列表的元素对进行迭代:
template <typename ...Types, typename ...Values> void f(type_list<Types...>, Values&&... values);
调用示例如下:
template <int i, typename T> struct P { static constexpr int i = i; using type = T; }; f(type_list<P<1, int>, P<3, double>>{}, 11, 12);
已知两个列表长度完全一致,且类型列表中的类型与值列表中的值无关联。请问是否可以将两个列表打包为类型/值对,再进行折叠操作?
回答
当然可以实现。核心思路是借助索引序列(std::index_sequence)来将类型列表和值列表的对应元素一一配对,之后就能对配对后的元素执行折叠操作。
具体实现步骤
编写辅助处理函数
先实现一个带索引序列的辅助函数,通过索引定位对应位置的类型和值,定义单对元素的处理逻辑:#include <utility> #include <tuple> #include <iostream> #include <typeinfo> // 处理单个类型/值对的模板函数 template <typename T, typename V> void process_single(T, V&& val) { // 示例操作:打印P类型的参数和对应值 if constexpr (requires { T::i; }) { std::cout << "P<" << T::i << ", " << typeid(typename T::type).name() << "> : " << val << "\n"; } } // 带索引序列的辅助函数 template <typename... Types, typename... Values, std::size_t... Is> void f_impl(type_list<Types...>, Values&&... values, std::index_sequence<Is...>) { // 将类型列表和值列表的对应元素配对,用折叠表达式迭代处理 (process_single(Types{}, std::get<Is>(std::forward_as_tuple(std::forward<Values>(values)...))), ...); }主函数转发到辅助函数
在主函数f中生成与类型列表长度匹配的索引序列,完成参数转发:template <typename... Types, typename... Values> void f(type_list<Types...>, Values&&... values) { static_assert(sizeof...(Types) == sizeof...(Values), "类型列表和值列表长度必须一致"); // 生成索引序列并调用辅助函数 f_impl(type_list<Types...>{}, std::forward<Values>(values)..., std::index_sequence_for<Types...>{}); }
关键说明
std::index_sequence_for<Types...>会自动生成长度为sizeof...(Types)的索引序列0,1,...,N-1,保证类型和值的位置一一对应。std::forward_as_tuple将值列表转为元组,通过std::get<Is>取出对应位置的值,和类型列表中Types[Is]配对。- 折叠表达式
(process_single(...), ...)会依次对每个类型/值对执行处理逻辑,实现迭代效果。
如果使用C++20及以上版本,也可以用模板lambda简化process_single的定义,省去单独写模板函数的步骤:
template <typename... Types, typename... Values, std::size_t... Is> void f_impl(type_list<Types...>, Values&&... values, std::index_sequence<Is...>) { auto process = []<typename T, typename V>(T, V&& val) { if constexpr (requires { T::i; }) { std::cout << "P<" << T::i << ", " << typeid(typename T::type).name() << "> : " << val << "\n"; } }; (process(Types{}, std::get<Is>(std::forward_as_tuple(std::forward<Values>(values)...))), ...); }
内容的提问来源于stack exchange,提问作者ridilculous
相关产品推荐
相关产品推荐

