创建两个可变参数的非类型模板参数包的笛卡尔积扩展 [英] Create cartesian product expansion of two variadic, non-type template parameter packs
问题描述
可以说,我有
- 两个非类型模板参数列表(可能有不同的类型)
- 一个模板
foo
,它将每个列表的一个值作为参数
- two lists of non-type template parameteres (which might have a different type)
- a template
foo
that takes one value of each of those lists as a parameter
如何创建 foo
的可变参数包,并使用两个列表元素的笛卡尔积进行参数化?
How can I create a variadic parameter pack of foo
s, parameterized with the cartesian product of the two list elements?
我的意思是:
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
的手动版本,并且可以将非类型参数列表作为数组提供,如果这可以简化代码.
I'm looking for a solution that works in c++11 and doesn't use any libraries except the c++11 standard library. I also have my handroled version of c++14's index_sequence
/ make_index_sequence
and can provide the non-type parameter lists as arrays if that simplifies the code.
到目前为止我发现的最接近的是:如何创建类型列表的笛卡尔积?.所以原则上(我没有测试过)应该可以将非类型参数包转换为类型参数包,然后在链接的帖子中应用解决方案,但我希望有一个更简单/更短的解决方案这行:
The closest I've found so far is this: How to create the Cartesian product of a type list?. So in principle (I haven't tested it) it should be possible to turn the non-type parameter packs into type parameter packs and then apply the solution in the linked post, but I was hoping that there is a simpler / shorter solution along the lines of this:
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{}));
标准部分的可能实现:
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...>{})
>...
>;
这篇关于创建两个可变参数的非类型模板参数包的笛卡尔积扩展的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!