I guess this is your first use of templates, so I'll try to be didactic.
You can think of template as some kind of type-aware macros. This type awareness is of course not to be neglected, since it grants type safety for free. This does mean however than template functions or classes are NOT functions or classes: they are model that will be used to generate functions or classes.
For example:
template <class T>
void foo(T t) { std::cout << t << "
"; }
This is a template function, it allows me to define something once and apply it to many different types.
int i;
foo(i); // [1]
This causes the instantiation of the template
. Basically, it means that a function is created according to the model, but replacing all occurrences of T
by int
.
double d;
foo(d); // Another instantiation, this time with `T` replaced by `double`
foo(d); // foo<double>() already exists, it's reused
Now, this idea of model is very important. If the definition of the model is not present in the header file, then the compiler does not know how to define the method.
So, you have 2 solutions here:
- Define it in the header
- Explicitly instantiate it
The 2 have different uses.
(1) is the classic way. It's easier because you don't restrict the user to a subset of the types. However it does mean that the user depends on the implementation (change it, she recompiles, and you need to pull the dependencies in the header)
(2) is less often used. For full compliance with the standard it requires:
- That you declare the specialization in the header (
template <> void foo<int>();
) so as to let the compiler know it exists
- That you fully define it in one of the translation units linked
The main advantage is that, like classic functions, you isolate the client from the implementation.
gcc
is quite lenient because you can forgo the declaration and it should work.
I should also note that it is possible to define a method twice, with different implementations. This is of course an error, as it is in direct violation of the ODR: One Definition Rule. However most linkers don't report it because it's quite common to have one implementation per object, and they just pick the first and assume the others will be equivalent (it's a special rule for templates). So if you do want to use explicit instantiation, take great care to only define it once.