下面的代码是合法的C(用g-Wall编译干净):
#ifdef MAKE_COMPILE
#define __restrict__ /* empty */
#define NO_FORWARD_DECLARATIONS
#endif
#include <stdio.h>
template <class T>
struct Array
{
int width, height;
T *ptr;
};
#ifdef HAVE_CUDA
template<typename T, int KernelSize>
static __global__ void genConvolve_kernel(const T __restrict__ * inputImageArray , T __restrict__ * outputImageArray , int inputWidth , int outputWidth )
{
if ((threadIdx.x == 4) && (threadIdx.y == 2))
printf("Hello world from CUDA!\n");
}
#endif
#ifndef NO_FORWARD_DECLARATIONS
template <typename T, int KernelSize>
void genConvolve_cuda(const Array<T> & kernelArray , const Array<T> & inputImageArray , Array<T> & outputImageArray , int blockWidth=16, int blockHeight=16);
template <typename T, int KernelSize>
void genConvolve_cuda_deviceptrs( const T __restrict__ * inputImageArray , T __restrict__ * outputImageArray , int inputWidth , int outputWidth , int outputHeight , int blockWidth=16, int blockHeight=16);
#endif
template <typename T, int KernelSize>
void genConvolve_cuda_deviceptrs( const T __restrict__ * inputImageArray , T __restrict__ * outputImageArray , int inputWidth , int outputWidth , int outputHeight , int blockWidth=16, int blockHeight=16)
{
#ifdef HAVE_CUDA
dim3 block(blockWidth,blockHeight);
dim3 grid(1,1);
genConvolve_kernel<T,KernelSize><<<grid,block>>>(inputImageArray,outputImageArray,inputWidth,outputWidth);
#else
printf("Hello, world!\n");
#endif
}
template <typename T, int KernelSize>
void genConvolve_cuda( const Array<T> & kernelArray , const Array<T> & inputImageArray , Array<T> & outputImageArray , int blockWidth=16, int blockHeight=16)
{
genConvolve_cuda_deviceptrs<T,KernelSize>((const T *)inputImageArray.ptr,outputImageArray.ptr, inputImageArray.width, outputImageArray.width, outputImageArray.height, blockWidth, blockHeight);
}
int main(int argc, char *argv[])
{
Array<float> a;
genConvolve_cuda<float,3>(a,a,a);
#ifdef HAVE_CUDA
cudaDeviceSynchronize();
#endif
return 0;
}
但是,当我尝试使用nvcc编译此文件时,会出现以下错误:
nvcc t.cu
t.cu(39):警告:当重新声明未引用的函数模板时,指定默认参数是不标准的
t、 cu(39):警告:重新定义默认参数
t.cu(51):警告:重新声明未引用的函数模板时指定默认参数是不标准的
t、 cu(51):警告:重新定义默认参数
t、 cu(53):错误:模板实例化导致在以下过程中检测到意外的函数类型“void(const-float*,float*,int,int,int,int,int,int)”(自模板声明以来,名称的含义可能已更改--模板的类型为“void(const-restrict-t*,-restrict-t*,int,int,int,int)”:基于模板参数的“genConvolve_cuda_deviceptrs”(53):这里是“void genConvolve_cuda(const数组)”的实例化
(当我在发布前清理示例时,行号会稍微偏移。)
当我定义-DMAKE_COMPILE时,警告和错误就会消失;但是,我确实希望在头文件中指定转发声明,并使用restrict!
所以两个问题:
如何在模板参数中正确使用\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
?
在与同事讨论后,有人向我指出,此\uuuu限制\uuuu
使用:
const T __restrict__ * inputImageArray ...
这是值得怀疑的。为了使\uuuu restrict\uuuu
产生任何效果,应将其置于星号和指针名称之间:
const T * __restrict__ inputImageArray ...
(gcc参考和CUDA参考)
在您所展示的非标准用法中,gcc似乎允许这样做,但默默地“放弃”了意图;在这种情况下,\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu限制
的效果不适用。在这方面,CUDA确实不同于gcc行为。但是,由于如上所述,它的使用存在疑问,因此不太可能修改nvcc
来“修复”此问题。
如果切换到标准\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
用法,可以使编译错误在显示的代码中消失。如果您的目的是向编译器声明这些实际上是受限制的指针,则建议这样做:
#ifdef MAKE_COMPILE
#define __restrict__ /* empty */
#define NO_FORWARD_DECLARATIONS
#endif
#include <stdio.h>
template <class T>
struct Array
{
int width, height;
T *ptr;
};
#ifdef HAVE_CUDA
template<typename T, int KernelSize>
static __global__ void genConvolve_kernel(const T * __restrict__ inputImageArray , T * __restrict__ outputImageArray , int inputWidth , int outputWidth )
{
if ((threadIdx.x == 4) && (threadIdx.y == 2))
printf("Hello world from CUDA!\n");
}
#endif
#ifndef NO_FORWARD_DECLARATIONS
template <typename T, int KernelSize>
void genConvolve_cuda(const Array<T> & kernelArray , const Array<T> & inputImageArray , Array<T> & outputImageArray , int blockWidth=16, int blockHeight=16);
template <typename T, int KernelSize>
void genConvolve_cuda_deviceptrs( const T * __restrict__ inputImageArray , T * __restrict__ outputImageArray , int inputWidth , int outputWidth , int outputHeight , int blockWidth=16, int blockHeight=16);
#endif
template <typename T, int KernelSize>
void genConvolve_cuda_deviceptrs( const T * __restrict__ inputImageArray , T * __restrict__ outputImageArray , int inputWidth , int outputWidth , int outputHeight , int blockWidth=16, int blockHeight=16)
{
#ifdef HAVE_CUDA
dim3 block(blockWidth,blockHeight);
dim3 grid(1,1);
genConvolve_kernel<T,KernelSize><<<grid,block>>>(inputImageArray,outputImageArray,inputWidth,outputWidth);
#else
printf("Hello, world!\n");
#endif
}
template <typename T, int KernelSize>
void genConvolve_cuda( const Array<T> & kernelArray , const Array<T> & inputImageArray , Array<T> & outputImageArray , int blockWidth=16, int blockHeight=16)
{
genConvolve_cuda_deviceptrs<T,KernelSize>((const T *)inputImageArray.ptr,outputImageArray.ptr, inputImageArray.width, outputImageArray.width, outputImageArray.height, blockWidth, blockHeight);
}
int main(int argc, char *argv[])
{
Array<float> a;
genConvolve_cuda<float,3>(a,a,a);
#ifdef HAVE_CUDA
cudaDeviceSynchronize();
#endif
return 0;
}
警告仍然存在;这似乎是另一个问题:
t986。cu(33):警告:在重新声明未引用的函数模板时指定默认参数是不标准的
t986.cu(33):警告:重新定义默认参数
t986.cu(45):警告:重新声明未引用的函数模板时指定默认参数是不标准的
t986.cu(45):警告:重新html" target="_blank">定义默认参数
如果默认(模板)函数参数包含在第一个声明中,而不是后续声明中,则可以使这些警告消失,如下所示:
#ifdef MAKE_COMPILE
#define __restrict__ /* empty */
#define NO_FORWARD_DECLARATIONS
#endif
#include <stdio.h>
template <class T>
struct Array
{
int width, height;
T *ptr;
};
#ifdef HAVE_CUDA
template<typename T, int KernelSize>
static __global__ void genConvolve_kernel(const T * __restrict__ inputImageArray , T * __restrict__ outputImageArray , int inputWidth , int outputWidth )
{
if ((threadIdx.x == 4) && (threadIdx.y == 2))
printf("Hello world from CUDA!\n");
}
#endif
#ifndef NO_FORWARD_DECLARATIONS
template <typename T, int KernelSize>
void genConvolve_cuda(const Array<T> & kernelArray , const Array<T> & inputImageArray , Array<T> & outputImageArray , int blockWidth=16, int blockHeight=16);
template <typename T, int KernelSize>
void genConvolve_cuda_deviceptrs( const T * __restrict__ inputImageArray , T * __restrict__ outputImageArray , int inputWidth , int outputWidth , int outputHeight , int blockWidth=16, int blockHeight=16);
#endif
template <typename T, int KernelSize>
void genConvolve_cuda_deviceptrs( const T * __restrict__ inputImageArray , T * __restrict__ outputImageArray , int inputWidth , int outputWidth , int outputHeight , int blockWidth, int blockHeight)
{
#ifdef HAVE_CUDA
dim3 block(blockWidth,blockHeight);
dim3 grid(1,1);
genConvolve_kernel<T,KernelSize><<<grid,block>>>(inputImageArray,outputImageArray,inputWidth,outputWidth);
#else
printf("Hello, world!\n");
#endif
}
template <typename T, int KernelSize>
void genConvolve_cuda( const Array<T> & kernelArray , const Array<T> & inputImageArray , Array<T> & outputImageArray , int blockWidth, int blockHeight)
{
genConvolve_cuda_deviceptrs<T,KernelSize>((const T *)inputImageArray.ptr,outputImageArray.ptr, inputImageArray.width, outputImageArray.width, outputImageArray.height, blockWidth, blockHeight);
}
int main(int argc, char *argv[])
{
Array<float> a;
genConvolve_cuda<float,3>(a,a,a);
#ifdef HAVE_CUDA
cudaDeviceSynchronize();
#endif
return 0;
}
虽然我同意这仍然不同于g行为。然而,gnu工具在这里可能仍然是不寻常的情况。默认参数的重新定义仍然出人意料,clang和cl.exe(microsoft)都会遇到问题。
This function is called when a template cannot be obtained from its resource. 该函数在模板不能从它的源目录下获取时会得到调用.
如果允许我执行以下操作: 为什么我主要不被允许做以下事情? 但我必须具体说明以下几点: C11引入了默认的模板参数,现在我完全无法理解它们。
是否允许在友元声明中为模板参数提供默认值? Visual Studio 2015似乎允许这样做。gcc拒绝了。我在cppreference页面上找不到任何内容。
函数模板、成员函数模板、或类模板的成员函数或静态数据成员的专门化可以在翻译单元内具有多个实例化点,并且除了上述实例化点之外,对于在翻译单元内具有实例化点的任何这样的专门化,翻译单元的末尾也被认为是实例化点。类模板的专门化在翻译单元中最多有一个实例化点。任何模板的专门化都可能在多个翻译单元中具有实例化点。如果两个不同的实例化点根据一个定义规则赋予一个模板专门化不同的含义,则程序是格式不良的,不需要诊
我想在模板类之外定义如下所述的函数。 已经为第二个参数尝试了很多组合,它是一个模板,并且也接受默认参数。 我希望它是在类之外定义的实际得到编译器错误,如果它是简单的类型,我可以很容易地在第二个参数中提到int、浮动等。
根据enable_if结构的定义: 我想知道怎么做 特别是: 在