gpt4 book ai didi

c++ - 创建两个可变的非类型模板参数包的笛卡尔积扩展

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:27:55 25 4
gpt4 key购买 nike

比方说,我有

  • 两个非类型模板参数列表(可能有不同的类型)
  • 一个模板foo,将每个列表的一个值作为参数

如何创建 foo 的可变参数包,并使用两个列表元素的笛卡尔积进行参数化?

我的意思是:

template<int ...>
struct u_list {};

template<char ...>
struct c_list {};

template<int, char >
struct foo {};

template<class ...>
struct bar {};

using int_vals = u_list<1, 5, 7>;
using char_vals = c_list<-3, 3>;


using result_t = /* magic happens*/
using ref_t = bar<
foo<1, -3>, foo<1, 3>,
foo<5, -3>, foo<5, 3>,
foo<7, -3>, foo<7, 3>
>;

static_assert(std::is_same<result_t, ref_t >::value, "");

我正在寻找一种适用于 c++11 且不使用除 c++11 标准库之外的任何库的解决方案。我也有我的 c++14 的 index_sequence/make_index_sequence 的 handroled 版本,如果简化代码,我可以提供非类型参数列表作为数组。

目前我找到的最接近的是:How to create the Cartesian product of a type list? .所以原则上(我还没有测试过)应该可以将非类型参数包转换为类型参数包,然后在链接的帖子中应用解决方案,但我希望有一个更简单/更短的解决方案这几行:

template<int... Ints, char ... Chars>
auto magic(u_list<Ints...>, c_list<Chars...>)
{
//Doesn't work, as it tries to expand the parameter packs in lock step
return bar<foo<Ints,Chars>...>{};
}

using result_t = decltype(magic(int_vals{}, char_vals{}));

最佳答案

您可以执行以下操作:

template <int... Is>
using u_list = std::integer_sequence<int, Is...>;

template <char... Cs>
using c_list = std::integer_sequence<char, Cs...>;

template<int, char> struct foo {};

template<class ...> struct bar {};

template <std::size_t I, typename T, template <typename, T...> class C, T ... Is>
constexpr T get(C<T, Is...> c)
{
constexpr T values[] = {Is...};
return values[I];
}


template <std::size_t I, typename T>
constexpr auto get_v = get<I>(T{});


template<int... Ints, char ... Chars, std::size_t ... Is>
auto cartesian_product(u_list<Ints...>, c_list<Chars...>, std::index_sequence<Is...>)
-> bar<foo<
get_v<Is / sizeof...(Chars), u_list<Ints...> >,
get_v<Is % sizeof...(Chars), c_list<Chars...> >
>...
>;

template<int... Ints, char ... Chars>
auto cartesian_product(u_list<Ints...> u, c_list<Chars...> c)
-> decltype(cartesian_product(u, c, std::make_index_sequence<sizeof...(Ints) * sizeof...(Chars)>()));




using int_vals = u_list<1, 5, 7>;
using char_vals = c_list<-3, 3>;

using result_t = decltype(cartesian_product(int_vals{}, char_vals{}));

Demo

标准部分的可能实现:

template <typename T, T ... Is> struct integer_sequence{};

template <std::size_t ... Is>
using index_sequence = integer_sequence<std::size_t, Is...>;

template <std::size_t N, std::size_t... Is>
struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};

template <std::size_t... Is>
struct make_index_sequence<0u, Is...> : index_sequence<Is...> {};

并更改答案:

template <std::size_t I, typename T, template <typename, T...> class C, T ... Is>
constexpr T get(C<T, Is...> c)
{
using array = T[];
return array{Is...}[I];
}

template<int... Ints, char ... Chars, std::size_t ... Is>
auto cartesian_product(u_list<Ints...>, c_list<Chars...>, index_sequence<Is...>)
-> bar<foo<
get<Is / sizeof...(Chars)>(u_list<Ints...>{}),
get<Is % sizeof...(Chars)>(c_list<Chars...>{})
>...
>;

Demo C++11

关于c++ - 创建两个可变的非类型模板参数包的笛卡尔积扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46831599/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com