[C++] Linker error when specializing over a parameterized type

7 replies to this topic

#1poita

Senior Member

• Members
• 322 posts

Posted 13 August 2009 - 01:12 AM

The following code gives me a linker error whenever the specialized version is used, specifically that the specialized version is multiply defined.

This code is all inside a header.

#ifndef GLEXTENSIONS_H

#define GLEXTENSIONS_H

#include <windows.h>

#include <gl/gl.h>

#include "Vector3.h"

template <typename V>

void glVertex(const V& v)

{

}

template <>

void glVertex< Math::Vector3f >(const Math::Vector3f& v)

{

glVertex3fv(&v.x);

}

#endif

// Note: Vector3f is defined (in the Math namespace):

// typedef Vector3<float> Vector3f;

Interestingly, I only get the linker error when the header is included by more than one file, but it is clearly guarded against multiple inclusions, so I don't understand how that could be causing an issue.

I get the feeling that it has something to do with the fact that I'm specializing over a type that is parameterized itself, but I can't seem to find any information regarding how to handle this (assuming I'm not handling it right already).

I'm using VC++05 v8.0

Homepage: http://poita.org

#2Reedbeta

DevMaster Staff

• 5310 posts
• LocationSanta Clara, CA

Posted 13 August 2009 - 01:27 AM

The problem is that the specialization causes the compiler to generate actual code, just like an ordinary non-template function. Thus, when you include this in multiple source files you get multiple definitions of that function. In contrast, a function template that is not fully specialized generates no code until it's instantiated.

One way to fix the problem is to mark the specialization inline; this causes it to have internal linkage and so the linker won't complain about it being multiply defined.

The other way would be to have only a prototype of the specialization in the header file, and leave its definition in a source file - again, just like an ordinary, non-template function.

poita said:

I get the feeling that it has something to do with the fact that I'm specializing over a type that is parameterized itself

I'm not quite sure what you mean - that the Vector3f type is itself an instantiation of a template? If so, there should be no need for special treatment, as it should function just like any other type.

However, if you would like to write a function template that can take a Vector of any dimension, you can do that as well, using what is called a "template template parameter", where the argument to a template is itself a template:

template <int n, template<int> typename V>
void myFunc(const V<n>& v)
{
// ...
}

reedbeta.com - developer blog, OpenGL demos, and other projects

#3poita

Senior Member

• Members
• 322 posts

Posted 13 August 2009 - 01:30 AM

But shouldn't the #ifndef guard prevent it from being generated twice?
Homepage: http://poita.org

#4poita

Senior Member

• Members
• 322 posts

Posted 13 August 2009 - 01:33 AM

Actually ignore that. Obviously it still gets generated twice because the file is getting included in two separate translation units, correct?
Homepage: http://poita.org

#5Reedbeta

DevMaster Staff

• 5310 posts
• LocationSanta Clara, CA

Posted 13 August 2009 - 01:39 AM

poita said:

Obviously it still gets generated twice because the file is getting included in two separate translation units, correct?

Yes.
reedbeta.com - developer blog, OpenGL demos, and other projects

#6.oisyn

DevMaster Staff

• Moderators
• 1842 posts

Posted 13 August 2009 - 01:25 PM

The One Definition Rule:
3.2/3

Quote

Every program shall contain exactly one definition of every non-inline function or object that is used in that
program; no diagnostic required. The definition can appear explicitly in the program, it can be found in the
standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and 12.8).
An inline function shall be defined in every translation unit in which it is used.

3.2/5

Quote

There can be more than one definition of a class type (clause 9), enumeration type (7.2), inline function
with external linkage (7.1.2), class template (clause 14), non-static function template (14.5.5), static data
member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template special-
ization for which some template parameters are not specified (14.7, 14.5.4) in a program provided that each
definition appears in a different translation unit, and provided the definitions satisfy the following require-
ments.

The specialization violates 3.2/3. The general template does not, as an exception is made for non-static function templates (but not their explicit specilializations) in 3.2/5
-
Currently working on: the 3D engine for Tomb Raider.

#7poita

Senior Member

• Members
• 322 posts

Posted 13 August 2009 - 01:47 PM

Quote

I'm not quite sure what you mean - that the Vector3f type is itself an instantiation of a template? If so, there should be no need for special treatment, as it should function just like any other type.

Yep, you're absolutely right. I was just being an idiot and looking at the wrong place :)

Quote

Note that you should even specify inline for the general template definition as well. Template function definitions are just as suspect to the One Definition Rule as every other function definition. The only practical difference is that most compilers don't complain about them.

Oh really?

Wait, so is there any (standard conforming) way of having a non-inline template function without using export, and without having to explicitly state which template instances you want instantiating? Or is the reason most compilers ignore it because of the fact that most compilers don't implement export?
Homepage: http://poita.org

#8.oisyn

DevMaster Staff

• Moderators
• 1842 posts

Posted 13 August 2009 - 02:25 PM

Quote

Oh really?
No. I edited my post . I was reading in 14/4 that "template definitions shall obey the one definition rule", which actually surprised me, but reading up on the actual ODR definition revealed the exception to the rule .