Inline template function referenced but not defined in CUDA 7.5 no warning in CUDA 6.5

I have just upgraded to CUDA 7.5 from CUDA 6.5 and I have a whole set of warnings that I didn’t have before that all follow the same form:

warning : function “TemplateClass::Method [with T=T]” was referenced but not defined

All of this compiled fine in CUDA 6.5. Can anyone tell me what I’m doing wrong or what the difference is? As an example:

template <typename T> struct TTuple3
{
	T x;
	T y;
	T z;

	__host__ __device__ __forceinline__ TTuple3<T>& operator+=(const TTuple3<T>& t)
	{ x += t.x; y += t.y; z += t.z; return *this; }

	__host__ __device__ __forceinline__ TTuple3<T>& Scale(const T factor)
	{ x *= factor; y *= factor; z *= factor; return *this; }
};

Calling this elsewhere with template type of float:

TTuple3<float> ptOne, ptTwo, ptAvg;
	ptOne.x = 1.0f;
	ptOne.y = 1.0f;
	ptOne.z = 1.0f;
	ptTwo.x = 2.0f;
	ptTwo.y = 2.0f;
	ptTwo.z = 2.0f;
	ptAvg .x = 0.0f;
	ptAvg .y = 0.0f;
	ptAvg .z = 0.0f;
	ptAvg += ptOne;
	ptAvg += ptTwo;
	ptAvg.Scale(0.5f);

I get warning : function “TTuple3::Scale [with T=T]” was referenced but not defined. Interestingly I don’t get any warning about operator+=(). Any ides?

Thanks,
Ewan

I was able to fix by adding a template declaration for the scalar parameter but this shouldn’t be required and opens the method up to abuse by allowing the caller to pass in types other than the template type:

template <typename S> __host__ __device__ __forceinline__ TTuple3<T>& Scale(const S factor)
	{ x *= factor; y *= factor; z *= factor; return *this; }

I’d still like to know why my original version is considered invalid by NVCC in CUDA 7.5 if anyone cares to comment?

Thanks,
Ewan

Your code as provided in your comment #1 in this thread compiled cleanly for me under CUDA 7.5, Fedora 20.

$ cat t1000.cu
template <typename T> struct TTuple3
{
        T x;
        T y;
        T z;

        __host__ __device__ __forceinline__ TTuple3<T>& operator+=(const TTuple3<T>& t)
        { x += t.x; y += t.y; z += t.z; return *this; }

        __host__ __device__ __forceinline__ TTuple3<T>& Scale(const T factor)
        { x *= factor; y *= factor; z *= factor; return *this; }
};

int main(){

TTuple3<float> ptOne, ptTwo, ptAvg;
        ptOne.x = 1.0f;
        ptOne.y = 1.0f;
        ptOne.z = 1.0f;
        ptTwo.x = 2.0f;
        ptTwo.y = 2.0f;
        ptTwo.z = 2.0f;
        ptAvg .x = 0.0f;
        ptAvg .y = 0.0f;
        ptAvg .z = 0.0f;
        ptAvg += ptOne;
        ptAvg += ptTwo;
        ptAvg.Scale(0.5f);

}
$ nvcc -o t1000 t1000.cu
$

Thanks for the update. Must be something else about my setup getting in the way then. I should have perhaps specified that I am using Visual Studio 2013 on Windows 8.1 Pro 64-bit.

Using the code posted by txbob, I do not see any warnings when compiling with CUDA 7.5, MSVC 2010, Windows 7 Professional 64-bit.

“referenced but not defined” issues would typically indicate that the compiler cannot “see” the definition of an object or function from the point where it is being used or instanced. Such an object would then presumably assumed to be external to the current compilation unit, which is unlikely to jibe with forceinline.

So the issue may be one of context in the form of code structure. It probably would make sense to shrink down your actual code to the minimal code that still reproduces the issue.

You are correct. I have created a simplified version of the code that does not exhibit the issue so I will need to try and pare back the actual code until it works to see where the issue lies. If I find out I will post a reply as whatever the issue is it did not occur with previous versions of CUDA so there must be a change somewhere.

I’m still a little bit puzzled as to why this would be a warning not an error. Surely if the compiler can’t see the definition of an inlined function then compilation should fail?

In any event thanks for your help, I will need to investigate further on my end.

Thanks,
Ewan

So as it turns out the warning was caused by another method in the header of another included template class calling the TTuple3Scale(float) method with a double argument. Presumably in previous versions type conversion was being applied silently but in this version a warning is being emitted. It would be more useful if the warning was the usual regarding a potentially unsafe cast/conversion but obviously the templates cloud the issue somewhat.

Thanks for your help,
Ewan