I propose you a C++14 solution that should be adapted for C++11 with substitutes for std::index_sequence
and std::make_index_sequence
.
I suggest, for applyAsDoubled()
, to simply call an helper function passing also a std::index_sequence
over the number of arrays
template <typename F, std::size_t N, typename ... As>
void applyAsDoubled (F f, As(&...as)[N])
{ applyAsDoubledH(f, std::make_index_sequence<sizeof...(As)>{}, as...); }
The helper function is heavily based over std::tuple
, to pack the copies of arrays, and new std::array
, for the C-style arrays copies
void applyAsDoubledH (F f, std::index_sequence<Is...> const & is,
Args(&...args)[N])
{
auto isn { std::make_index_sequence<N>{} };
std::tuple<std::array<Args, N>...> tpl { getStdArray(args, isn)... };
doublerMutation(tpl, is);
for (auto ui { 0u } ; ui < N ; ++ui )
f(std::get<Is>(tpl)[ui]...);
}
Observe the calls to getStdArray()
template <typename T, std::size_t N, std::size_t ... Is>
std::array<T, N> getStdArray (T(&a)[N], std::index_sequence<Is...> const &)
{ return { { a[Is]... } }; }
to get the singles std::array
form singles C-style array.
The doublerMutation()
also uses a helper function
template <std::size_t I, std::size_t N, typename ... Args>
void doublerMutationH (std::tuple<std::array<Args, N>...> & tpl)
{
for ( auto ui { 0u } ; ui < N ; ++ui )
std::get<I>(tpl)[ui] *= 2;
}
template <std::size_t N, typename ... Args, std::size_t ... Is>
void doublerMutation (std::tuple<std::array<Args, N>...> & tpl,
std::index_sequence<Is...> const &)
{
using unused = int[];
(void) unused { 0, (doublerMutationH<Is>(tpl), 0)... };
}
The following is a full working example
#include <tuple>
#include <array>
#include <iostream>
#include <type_traits>
template <std::size_t I, std::size_t N, typename ... Args>
void doublerMutationH (std::tuple<std::array<Args, N>...> & tpl)
{
for ( auto ui { 0u } ; ui < N ; ++ui )
std::get<I>(tpl)[ui] *= 2;
}
template <std::size_t N, typename ... Args, std::size_t ... Is>
void doublerMutation (std::tuple<std::array<Args, N>...> & tpl,
std::index_sequence<Is...> const &)
{
using unused = int[];
(void) unused { 0, (doublerMutationH<Is>(tpl), 0)... };
}
template <typename T, std::size_t N, std::size_t ... Is>
std::array<T, N> getStdArray (T(&a)[N], std::index_sequence<Is...> const &)
{ return { { a[Is]... } }; }
template <typename F, std::size_t ... Is, std::size_t N, typename ... Args>
void applyAsDoubledH (F f, std::index_sequence<Is...> const & is,
Args(&...args)[N])
{
auto isn { std::make_index_sequence<N>{} };
std::tuple<std::array<Args, N>...> tpl { getStdArray(args, isn)... };
doublerMutation(tpl, is);
for (auto ui { 0u } ; ui < N ; ++ui )
f(std::get<Is>(tpl)[ui]...);
}
template <typename F, std::size_t N, typename ... As>
void applyAsDoubled (F f, As(&...as)[N])
{ applyAsDoubledH(f, std::make_index_sequence<sizeof...(As)>{}, as...); }
int main ()
{
int A[] = { 1, 2, 3, 4, 5 };
long B[] = { 2, 2, 2, 2, 2 };
auto printSum = [](auto const & ... as)
{
using unused = int[];
typename std::common_type<decltype(as)...>::type sum {};
(void)unused { 0, (sum += as, 0)... };
std::cout << "the sum is " << sum << std::endl;
};
applyAsDoubled(printSum, A, B);
}
If you can also use C++17, using template folding and the power of comma operator, you can avoid the use of unused
s array and doublerMutation()
can be simplified as follows
template <std::size_t N, typename ... Args, std::size_t ... Is>
void doublerMutation (std::tuple<std::array<Args, N>...> & tpl,
std::index_sequence<Is...> const &)
{ ( doublerMutationH<Is>(tpl), ... ); }
and the printSum()
lambda test function as follows
auto printSum = [](auto const & ... as)
{ std::cout << "the sum is " << (as + ...) << std::endl; };