模板列表和用于实例化它们的类型列表的笛卡尔积

Cartesian product of list of templates and list of types to instantiate them with

不确定标题是否具有描述性,但我想要的是:

输入:

  1. 模板列表(在我的例子中是容器)接受 1 个(必需的,可以是更多可选的)类型参数
  2. 类型列表

输出:

“笛卡尔积”,其中第一组中的每个模板都用第二组中的每种类型实例化。

示例:

template_list<std::vector, std::set> x type_list<int, double> => 
type_list<std::vector<int>, std::vector<double>, std::set<int>, std::set<double>>

我发现了这个问题,但这是关于两个集合的元素都是类型的情况。

How to create the Cartesian product of a type list?

我想如果没有宏我想要的是不可能的,但我可能遗漏了一些东西。

你可以使用 std::tuples. Especially std::tuple_cat 这很好。

示例:

#include <iostream>
#include <set>
#include <tuple>
#include <type_traits>
#include <vector>

template <template <class...> class... C>
struct template_list {};

template <template <class...> class C, class... Ts>
auto toc(const std::tuple<Ts...>&) {
    return std::tuple<C<Ts>...>{};
}

template <template <class...> class... C, class... Ts>
auto operator*(template_list<C...>, const std::tuple<Ts...>& tup) {
    return std::tuple_cat(toc<C>(tup)...);
}

int main() {
    template_list<std::vector, std::set> templ;
    std::tuple<int, double, float> typel;

    auto res = templ * typel;

    static_assert(
        std::is_same_v<decltype(res),
                       std::tuple<std::vector<int>, std::vector<double>,
                                  std::vector<float>, std::set<int>,
                                  std::set<double>, std::set<float>>>);
}

Demo


一个类似的解决方案变成了一个更经典的类型特征,其中 res 将导致与上面相同的类型可能如下所示:

template <template <class...> class... C>
struct template_list {};

template <class Temps, class Types>
struct cartesian_product {
    
    template <template <class...> class C, class... Ts>
    static std::tuple<C<Ts>...> toc(const std::tuple<Ts...>&);
    
    template <template <class...> class... C, class... Ts>
    static auto build(template_list<C...>, const std::tuple<Ts...>& tup)
        -> decltype(std::tuple_cat(std::declval<decltype(toc<C>(tup))>()...));

    using type = decltype(build(std::declval<Temps>(), std::declval<Types>()));
};

template<class Temps, class Types>
using cartesian_product_t = typename cartesian_product<Temps,Types>::type;
int main() {
    using templt = template_list<std::vector, std::set>;
    using typelt = std::tuple<int, double, float>;

    cartesian_product_t<templt, typelt> res;
}

正如我对他链接问题的回答,Boost.Mp11,这是一个简短的 one-liner(一如既往):

using templates = mp_list<mp_quote<std::vector>, mp_quote<std::set>>;
using types = mp_list<int, double>;

using result = mp_product<
    mp_invoke_q,
    templates, types>;

static_assert(std::same_as<
    result,
    mp_list<std::vector<int>,
            std::vector<double>,
            std::set<int>,
            std::set<double>
            >>);

Demo.

请注意,您需要 templates 作为 mp_list<mp_quote<C1>, mp_quote<C2>> 而不是 template_list<C1, C2>,因为如果一切都是类型,元编程会容易得多。但这并不是一个巨大的负担。