将数组/指针作为模板参数传递

时间:2011-04-08 07:43:43

标签: c++ arrays templates parameters cuda

我正在尝试创建以下类型的模板函数:

template <bool isHorizontal, float* kernel>
__global__ void smoothFilterColumns(const TwImageCUDA_Device* source, TwImageCUDA_Device* 
destination)
{
// code...
}

(不要担心__global__;这是在CUDA上实现的。)

不幸的是,它不允许我像这样创建这个函数的实例:

float ptrKernel[] = {1, 2, 1};
smoothFilterColumns<true, ptrKernel>(dxBuffer->cuda_image, dxOutput->cuda_image);

我尝试了各种float*float[] s,包括和不包含const修饰符。甚至可以创建这种模板吗?

提前致谢。

NB。内核作为模板参数传递,而不是普通的函数参数,因为这允许我通过展开循环在CUDA中创建更高效​​的代码。

更新使用标准C ++作为模板参数的浮点数工作,但显然没有办法让它们与CUDA设备函数一起使用,因为它们需要指向设备地址的指针而且无法从外部定义。如果有人这样做,请告诉我。

5 个答案:

答案 0 :(得分:3)

我怀疑你会这样做。正如其他人指出的那样,C ++标准规定,作为模板参数传递的任何对象或函数都必须具有外部链接(因此未在当前转换单元的范围内定义)。问题是CUDA目前根本不支持外部链接 - 设备代码中使用的每个符号都必须具有内部链接(即在同一个翻译单元中定义)。这种限制的根本原因是CUDA目前没有设备代码的链接器。

答案 1 :(得分:2)

请确保ptrKernel有外部链接。

// static float ptrKernel[] = { ... };
// ^ won't work.

// const float ptrKernel[] = { ... };
// ^ won't work.

float ptrKernel[] = { ... };
// ^ ok.

void func() {
   // float ptrKernel[] = { ... };
   // ^ won't work (not global variable).
   ...
}

这是对非类型模板的限制,如§[temp.arg.nontype] / 1中所述:

  

非类型非模板模板参数 template-argument 应为以下之一:

     
      
  • 整数或枚举类型的整数常量表达式;或
  •   
  • 非类型模板参数的名称;或
  •   
  • 具有外部链接的对象或函数的名称,包括函数模板和函数 template-id ,但不包括非静态类成员,表示为 ID-表达;或
  •   
  • 具有外部链接的对象或函数的地址,包括函数模板和函数 template-id ,但不包括非静态类成员,表示为{{ 1}} id-expression 如果名称引用函数或数组,则&是可选的;或
  •   
  • 指向成员的指针,如5.3.1所述。
  •   

答案 2 :(得分:2)

我猜你传递的ptrKernel变量作为模板参数是一个局部变量。无论如何,对于您可以作为非类型模板参数传递的内容存在限制。根据C ++标准(14.3.2),允许以下内容:

  • 整数或枚举类型的整数常量表达式
  • 非类型模板参数的名称
  • 具有外部链接的对象或功能的名称
  • 具有外部链接的对象或功能的地址
  • 指向成员的指针

确保ptrKernel变量满足这些要求(同样,我的猜测是它不是具有外部链接的变量,即全局或静态类成员)。

答案 3 :(得分:0)

这会在CUDA中发挥作用吗?

template <bool isHorizontal, class Kernel>
__global__ void smoothFilterColumns(
    const TwImageCUDA_Device* source, TwImageCUDA_Device* destination)
{
    const float *kernel = Kernel::ptr();
    // code...
}

struct Kernel_1_2_1
{
    static const float *ptr()
    {
        static const float kernel[] = {1, 2, 1};
        return kernel;
    }
}

smoothFilterColumns<true, Kernel_1_2_1>(
    dxBuffer->cuda_image, dxOutput->cuda_image);

您可以将内核设为struct的数据成员。您可能希望添加一种机制来传递内核大小。

答案 4 :(得分:0)

不会工作。您正在尝试将CPU-RAM指针传递给GPU-RAM内核。

您可以采用不同的方式1)使用多个模板嵌入所有常量值 取决于你的内核的不同长度,或者你 创建一个functor类来处理要应用的转换的细节:

这是一个让你了解的工作示例。不要忘记设备说明符。

// with 3 int
template<int amount, int k0,int k1, int k2>
__global__ void apply_kernel(const float *input, float *output){


}

// with four int
template<int amount, int k0,int k1, int k2, int k3>
__global__ void apply_kernel(const float *input, float *output){


}

// with five int 
template<int amount, int k0,int k1, int k2, int k3, int k4>
__global__ void apply_kernel(const float *input, float *output){


}

class KernelOperator {
public:
      __host__ __device__ KernelOperator() {
      }
      __host__ __device__ int operator*(int value){
            return value * 2;
      }
};


// with KernelOperator
template<class T>
__global__ void apply_kernel(const float *input, float *output){
           T value;

}

int main(){
    apply_kernel<0, 1,2,1><<<10, 20>>>(NULL,NULL);

    apply_kernel< KernelOperator ><<<10, 20>>>(NULL,NULL);
}