Повторяющийся параметр шаблона переменной - PullRequest
0 голосов
/ 29 августа 2018

Контекст:

Я младший инженер-программист, надеюсь, я не изобретаю колесо, пожалуйста, дайте мне знать. Я хотел бы создать шаблонную функцию, которая оборачивает и вызывает другую функцию с точки зрения элемента. Например:

// 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-м кортеже параметра массива variadic, например, о zipping в python. EX (не реальный код):

template<typename... Args, size_t N>
void bar(Args(&...argsarray)[N]) {
  // (python) ithvariadic = zip(*argsarray)[i]
  auto ithvariadic = argsarray[i]...;
}

1 Ответ

0 голосов
/ 29 августа 2018
  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
    }
 }

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...