我正在尝试创建以下类型的模板函数:
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设备函数一起使用,因为它们需要指向设备地址的指针而且无法从外部定义。如果有人这样做,请告诉我。
答案 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);
}