Is there a way to explicitly specify which ...
refers to which pack expansion? In my code I have two pack expansions that I want to apply at different levels:
template<typename T, int N>
struct MyArr
{
T e[N];
constexpr T& operator[](int i) { return e[i]; }
constexpr const T& operator[](int i) const { return e[i]; }
MyArr() : e{} {}
template<typename ...type_pack>
MyArr(const type_pack&... pack) : e{pack...}
{
static_assert(sizeof...(pack)==N,
"Argument count must match the size.");
}
};
template<typename type_lhs, typename type_rhs>
auto add(const type_lhs& lhs, const type_rhs& rhs)
{
return lhs + rhs;
}
template<int ...I, typename type_head, typename ...type_pack, int N, typename Function>
auto apply(Function&& op,
const MyArr<type_head,N>& head, const MyArr<type_pack,N>&... pack)
{
return MyArr<type_head,N>((op(head[I],(pack[I])...))...);
// expand pack[I]- ^ , ^ - expand I...
};
int main()
{
MyArr<int,3> a(1,2,3);
return apply<0,1,2>(add<int,int>, a, a);
}
Essentially, I want to get:
(op(head[0], get<0>(pack)[0], ..., get<M-1>(pack)[0]),
...,
op(head[N-1], get<0>(pack)[N-1], ..., get<M-1>(pack)[N-1]))
Thanks to OznOg's advice I got it to work through creating a function in the middle:
template<int ...I, typename type_head, typename ...type_pack, int N, typename Function>
auto apply(Function&& op,
const MyArr<type_head,N>& head, const MyArr<type_pack,N>&... pack)
{
auto op2 = [&](int i) { return op(head[i], pack[i]...);};
return MyArr<type_head,N>(op2(I)...);
};
In this particular case, the only way I see is the use of an helper function (getVal()
, in the following example)
template <int I, typename type_head, typename ...type_pack, int N,
typename Function>
auto getVal (Function&& op, MyArr<type_head,N> const & head,
MyArr<type_pack,N> const & ... pack)
{ return op(head[I], pack[I]...); }
template <int ... Is, typename type_head, typename ...type_pack, int N,
typename Function>
auto apply (Function && op, MyArr<type_head,N> const & head,
MyArr<type_pack,N> const &... pack)
{ return MyArr<type_head,N>{ getVal<Is>(op, head, pack...)... }; }
The problem is that you have
(pack[I])...
so there is no way (as far I know) to say that the expansion is to be applied to pack
and not to I
.
With the intermediate function
//.......................VVV expand pack
getVal<Is>(op, head, pack...)...
//...........................^^^ expand Is
you can use parentheses to separate the levels.
But you have to separate pack
and Is
.