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

重复变量模板参数

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

    背景:

    我是一名Jr软件工程师,希望我不是在重新发明轮子,请告诉我。 我想创建一个模板函数,它包装并调用另一个函数元素。例如:

    // returns a*x + y
    __device__ float saxpy(float a, float x, float y) {
      return a*x + y;
    }
    
    
    int main() {
      int A[4] = { 1,2,3,4 };
      int X[4] = { 1,2,3,4 };
      int Y[4] = { 1,1,1,1 };
    
      // A*X   = 1,4,9,16
      // A*X+Y = 2,5,10,17
      float *C = cudaReduce(saxpy, A, X, Y);
    
      for (int i = 0; i < 4; i++)
        printf("%d, ", C[i]); // should print "2, 5, 10, 17, "
    
      std::cin.ignore();
      return 0;
    }
    

    重要的是,我想创建这个包装器,以便在执行元素操作时很好地包装cuda调用。虽然非常不完整,但下面是我对函数包装器的伪代码尝试。

    我想提供一个简单的例子;然而,我几乎不知道如何去C++的某些方面,所以请原谅大量评论的伪代码:

    #include "cuda_runtime.h"
    #include "device_launch_parameters.h"
    
    #include <iostream>
    
    // returns a*x + y
    __device__ float saxpy(float a, float x, float y) {
      return a*x + y;
    }
    
    // finds return type of function pointer
    template<typename R, typename... A>
    R ret(R(*)(A...));
    template<typename C, typename R, typename... A>
    R ret(R(C::*)(A...));
    
    template<typename F, size_t N, typename... Args>
    auto cudaReduce(F &f, Args(&...argsarray)[N]) {
      cudaSetDevice(0);
    
      // ret is function f's return type
      typedef decltype(ret(f)) ret;
      ret d_out[N], h_out[N];
      // cudaMalloc((void**)&d_out, sizeof(d_out));
      sendToCuda(argsarray...); // allocates and copies all contents of argsarray to cuda
    
      // reduceKernel<<<1, N>>>(f, d_out, dev_argsarray...);
    
      // cudaDeviceSynchronize();
      // cudaMemcpy(h_out, d_out, sizeof(h_out), cudaMemcpyDeviceToHost);
      // cudaFree(d_out);
    
      // for d_args in d_argsarray
      //   cudaFree(d_args);
    
      return h_out;
    }
    
    template<typename F, size_t N, typename Out, typename... Args>
    __global__ void cudaReduceKernel(F &f, Out(&out)[N], Args(&...argsarray)[N]) {
      int tid = threadIdx.x;
      int i = tid + blockIdx.x * blockDim.x;
    
      // Below is invalid syntax; however, the 'pseudo-code' is what I'd like to achieve.
      // out[i] = f(argsarray[i]...);
    }
    
    // cuda malloc and memcpy
    template<typename Arg, size_t N>
    void sendToCuda(Arg(&args)[N]) {
      size_t buffer = sizeof(args);
      //cudaMalloc((void**)&dev_arg[ ??? ], buffer);
      //cudaMemcpy((void**)&dev_arg[ ??? ], args, buffer, cudaMemcpyHostToDevice);
    }
    template<typename Arg, size_t N, typename... Args>
    void sendToCuda(Arg(&args)[N], Args(&...argsarray)[N]) {
      sendToCuda(args);
      sendToCuda(argsarray...);
    }
    
    int main() {
      int A[4] = { 1,2,3,4 };
      int X[4] = { 1,2,3,4 };
      int Y[4] = { 1,1,1,1 };
    
      // A*X   = 1,4,9,16
      // A*X+Y = 2,5,10,17
      float *C = cudaReduce(saxpy, A, X, Y);
    
      for (int i = 0; i < 4; i++)
        printf("%d, ", C[i]); // should print "2, 5, 10, 17, ", currently prints undefined behaviour
    
      std::cin.ignore();
      return 0;
    }
    

    我意识到并不是每个人都有时间彻底检查代码,所以我将把关键问题归结为几点:

    1. 是否可以复制可变模板输入,如果可以,如何复制? EX(非真实代码):

    template<typename... Args>
    void foo(Args... args) {
      Args... args2;
    }
    

    这是必要的,这样我就可以复制我的输入参数到我的cuda的输入参数 malloc() memcpy() .

    2. 我将如何处理可变数组参数的第I个元组,比如python中的压缩。 EX(非真实代码):

    template<typename... Args, size_t N>
    void bar(Args(&...argsarray)[N]) {
      // (python) ithvariadic = zip(*argsarray)[i]
      auto ithvariadic = argsarray[i]...;
    }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   max66    7 年前
    1. 是否可以复制可变模板输入,如果可以,如何复制?EX(非真实代码):
    template <typename... Args>
     void foo(Args... args) {
      Args2... args;
     }
    

    不是那样的。

    这个 Args... 字体名称是免赔额 args... 参数。

    但是关于 Args2... ? 你怎么能推断出它们呢?你想解释一下吗?

    但是你确定你需要不同的类型吗?

    如果不需要不同的类型列表,我能想象的最好的方法就是使用元组,正如Jarod42所建议的那样

    如下

    template <typename ... Args>
    void foo (Args ... args)  
     {
       std::tuple<Args...> tpl { args... };
    
       // do something with tpl`
     }
    

    或者,如果你想实现完美的转发,

    template <typename ... Args>
    void foo (Args && ... args)  
     {
       std::tuple<Args...> tpl { std::forward<Args>(args)... };
    
       // do something with tpl`
     }
    
    1. 我将如何处理可变数组参数的第I个元组,比如python中的压缩。EX(非真实代码):
    template<typename... Args, size_t N>
    void bar(Args(&...argsarray)[N]) {
      // (python) ithvariadic = zip(*argsarray)[i]
      auto ithvariadic = argsarray[i]...;
    }
    

    那么...怎么样

    template <typename ... Args, std::size_t N>
    void bar (Args (&...argsarray)[N])
     {
       for ( auto ui = 0u ; ui < N ; ++ui )
        {
          std::tuple<Args...> ithvariadic { argsarray[ui]... };
    
          // do something with ithvariadic
        }
     }
    

    ?