Boost MP11:如何从类型索引容器生成类型列表?
问题解答
核心结论
- 直接从运行时确定值的
std::array<std::size_t>生成MyType<Baz, Bar, Foo>或MyType<2,1,0>这类编译期模板类型不可行——因为模板参数必须是编译期常量,而运行时数值无法提升为编译期常量。 - 若索引容器是编译期常量(
constexpr修饰),则两种需求都可以实现。
场景1:索引为编译期常量(可行)
如果arr的值在编译时就已知,我们可以通过编译期工具链将其转换为目标类型。
生成MyType<2,1,0>(索引直接作为模板参数)
#include <boost/mp11/mp_list.hpp> #include <array> #include <utility> template<std::size_t... Is> struct MyType {}; // 辅助工具:将constexpr数组转换为整数序列 template<typename Array, std::size_t... I> constexpr auto array_to_seq(const Array& arr, std::index_sequence<I...>) { return std::integer_sequence<std::size_t, arr[I]...>{}; } template<typename Array> constexpr auto array_to_seq(const Array& arr) { return array_to_seq(arr, std::make_index_sequence<Array::size()>{}); } // 从整数序列生成MyType实例 template<typename Seq> struct seq_to_mytype; template<std::size_t... Is> struct seq_to_mytype<std::integer_sequence<std::size_t, Is...>> { using type = MyType<Is...>; }; // 使用示例 constexpr std::array<std::size_t, 3> arr{2, 1, 0}; using MyTypeFromIndices = seq_to_mytype<decltype(array_to_seq(arr))>::type; // MyTypeFromIndices 等价于 MyType<2,1,0>
生成MyType<Baz, Bar, Foo>(索引对应类型作为模板参数)
#include <boost/mp11/mp_list.hpp> #include <boost/mp11/mp_at.hpp> #include <array> #include <utility> struct Foo {}; struct Bar {}; struct Baz {}; using List = boost::mp11::mp_list<Foo, Bar, Baz>; template<typename... Ts> struct MyType {}; // 辅助工具:将constexpr数组转换为整数序列(复用上面的array_to_seq) template<typename Array, std::size_t... I> constexpr auto array_to_seq(const Array& arr, std::index_sequence<I...>) { return std::integer_sequence<std::size_t, arr[I]...>{}; } template<typename Array> constexpr auto array_to_seq(const Array& arr) { return array_to_seq(arr, std::make_index_sequence<Array::size()>{}); } // 从整数序列映射到List中的对应类型,生成MyType实例 template<typename List, typename Seq> struct indices_to_types; template<typename List, std::size_t... Is> struct indices_to_types<List, std::integer_sequence<std::size_t, Is...>> { using type = MyType<typename boost::mp11::mp_at_c<List, Is>::type...>; }; // 使用示例 constexpr std::array<std::size_t, 3> arr{2, 1, 0}; using MyTypeFromTypes = indices_to_types<List, decltype(array_to_seq(arr))>::type; // MyTypeFromTypes 等价于 MyType<Baz, Bar, Foo>
场景2:索引为运行时确定值(仅能运行时处理)
如果arr的值是运行时才确定的(比如来自用户输入、文件读取),无法生成编译期的MyType模板实例,只能通过运行时多态或std::variant来处理类型组合:
#include <boost/mp11/mp_list.hpp> #include <boost/mp11/mp_with_index.hpp> #include <array> #include <variant> struct Foo {}; struct Bar {}; struct Baz {}; using List = boost::mp11::mp_list<Foo, Bar, Baz>; using TypeVariant = std::variant<Foo, Bar, Baz>; std::array<std::size_t, 3> arr{2, 1, 0}; // 运行时赋值的索引 // 将每个索引转换为对应类型的variant对象 std::array<TypeVariant, 3> type_variants; for (std::size_t i = 0; i < arr.size(); ++i) { boost::mp11::mp_with_index<boost::mp11::mp_size<List>::value>( arr[i], [&](auto I) { type_variants[i] = typename boost::mp11::mp_at_c<List, I>::type{}; } ); } // 后续可通过std::visit处理variant中的具体类型
内容的提问来源于stack exchange,提问作者Archduke
相关产品推荐
相关产品推荐

