对类型列表进行递归迭代并连接到结果类型列表中

Recursive iteration over type lists and concatenation into a result type list

考虑一个具有各种 classes/structs 的场景,其中一些具有复杂的数据成员,这些成员本身可以包含更多。为了设置/初始化,在实例化之前需要所有依赖项的列表。

因为类型在实例化之前是已知的,我的方法是定义一个类型列表,其中每个 class/struct 包含 involved/relevant 类型,如下所示:

template<typename...> struct type_list {};

struct a {
    using dependencies = type_list<>;
};

struct b {
    using dependencies = type_list<>;
};

struct c {
    using dependencies = type_list<b>;
    b b_;
};

struct d {
    using dependencies = type_list<a>;
    a a_;
};

struct e {
    using dependencies = type_list<c, a>;
    c c_;
    a a_;
    x x_; // excluded
};

struct f {
    using dependencies = type_list<a,b>;
    a a_;
    b b_;
    y y_; // excluded
};

比如我想预初始化d, e, f.

接下来的步骤是:

结果可能包含重复项。这些在后面的步骤中被减少和排序。我打算使用 constexpr 散列映射使用 __FUNCSIG__ / __PRETTY_FUNCTION__ 的散列(不是其中的一部分)来执行此操作。

如何使用 C++20 元编程实现这一点(迭代、访问类型列表元素、连接到结果列表)?

我只看元编程部分。一如既往,解决方案是使用 Boost.Mp11。在这种情况下,它是更复杂的算法之一:mp_iterate.

这将一个函数应用于一个值直到失败 - 这就是我们实现递归的方式。我们需要几个步骤。

首先,元函数获取单个类型的依赖关系

template <typename T> using dependencies_of = typename T::dependencies;

然后,我们需要一种方法来获取类型列表的所有依赖项。重要的是,这需要在某些时候失败(对于 mp_iterate 的停止条件),因此我们在空列表上强制失败:

template <typename L>
using list_dependencies_of = std::enable_if_t<
    not mp_empty<L>::value,
    mp_flatten<mp_transform<dependencies_of, L>>>;

然后我们可以使用这些片段进行迭代:

template <typename L>
using recursive_dependencies_of = mp_unique<mp_apply<mp_append,
    mp_iterate<
        L,
        mp_identity_t,
        list_dependencies_of
        >>>;

mp_append 连接了 mp_iterate 给你的列表列表,然后 mp_unique 在上面,因为你不想重复。

这需要一个列表,所以可以像 recursive_dependencies_of<mp_list<a>>(就是 mp_list<a>)或 recursive_dependencies_of<mp_list<d, e, f>>(就是 mp_list<d, e, f, a, c, b>)那样使用。

Demo.