You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Boost MP11:如何从类型索引容器生成类型列表?

问题解答

核心结论

  1. 直接从运行时确定值的std::array<std::size_t>生成MyType<Baz, Bar, Foo>或MyType<2,1,0>这类编译期模板类型不可行——因为模板参数必须是编译期常量,而运行时数值无法提升为编译期常量。
  2. 若索引容器是编译期常量(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 05:37:05