代码之家  ›  专栏  ›  技术社区  ›  Michael Choi Peter Alexander

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

  •  1
  • Michael Choi Peter Alexander  · 技术社区  · 7 年前

    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 A B doublerMutation() 是一个伪函数,用于表示将导致参数突变且无法重写的函数。

    1 回复  |  直到 7 年前
        1
  •  1
  •   max66    7 年前

    我建议你用C++ 14解决方案,它应该适合C++ 11,并用替代品 std::index_sequence std::make_index_sequence

    我建议,为了 applyAsDoubled() ,只需调用传递 超过数组数

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

    helper函数主要基于 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::数组 形成singles 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,使用模板折叠和逗号运算的幂,可以避免使用 unused 双重置换() 可以简化如下

    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()

    auto printSum = [](auto const & ... as)
     { std::cout << "the sum is " << (as + ...) << std::endl; };