是否可以定义模板参数包数组

问题描述 投票:1回答:1

可能重复:Is it possible to "store" a template parameter pack without expanding it?

与上面的问题类似,我想更多地探讨这个并存储一个可变数组。

template<size_t N, typename... Args>
void foo(Args(&...args)[N]) {
  Args[N]... args2; // compilation error
}

这有可能实现吗?

最终目标是能够调用foo(),改变其可变数组输入的副本,并对突变执行一些功能。所以,像:

template<typename F, size_t N, typename... Args>
void applyAsDoubled(F f, Args(&...args)[N]) {
  Args[N]... args2;
  doublerMutation(args2...); // doubles each argument; external function, assume it cannot avoid having a side-effect on its parameters

  for (int i = 0; i < N; i++)
    f(args2[i]...);
}

将打电话,没有副作用:

int A[N] = { 1, 2, 3, 4, 5 };
int B[N] = { 2, 2, 2, 2, 2 };

applyAsDoubled(printAdded, A, B);

将打印6,8,10,12,14,其中AB没有变异。只是为了澄清,函数doublerMutation()是一个虚函数,用于表示一个函数,该函数将导致参数的突变并且不能被重写。

c++11 templates variadic-templates variadic-functions template-meta-programming
1个回答
1
投票

我建议你一个C ++ 14解决方案,应该适用于C ++ 11,替代std::index_sequencestd::make_index_sequence

对于applyAsDoubled(),我建议简单地调用辅助函数,在数组的数量上传递std::index_sequence

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...); }

辅助函数主要基于std::tuple,用于打包数组的副本,以及新的std::array,用于C风格的数组副本

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]...);
 }

观察对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]... } }; }

获得单打std::array形式的单曲C风格阵列。

doublerMutation()也使用辅助函数

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)... };
 }

以下是一个完整的工作示例

#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);
 }

如果你也可以使用C ++ 17,使用模板折叠和逗号运算符的强大功能,你可以避免使用unuseds数组和doublerMutation()可以简化如下

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), ... ); }

printSum() lambda测试功能如下

auto printSum = [](auto const & ... as)
 { std::cout << "the sum is " << (as + ...) << std::endl; };
© www.soinside.com 2019 - 2024. All rights reserved.