I'm getting consistent behavior from both gcc 4.8.3 and clang 3.2, but do not understand why it is happening. Despite the fact that I have an explicit instantiation for a class template, the code is not being generated and I get an undefined symbol when I am using a fully specialized instance of the template.
I have a simple class template definition in a file 'temp.hpp'
#pragma once
template <typename T1>
class C
{
public:
C (T1 c) : d_c(c) {};
~C () = default;
void print ();
private:
T1 d_c;
};
Note that the method 'print()' is declared, but not defined here. I want the definition in the .cpp file and it will be specialized for different types.
So in the temp.cpp file I have the default definition of the print() method
#include "temp.hpp"
#include <iostream>
template<typename T1>
void
C<T1>::print ()
{
std::cout << "Printing: " << d_c << std::endl;
}
followed by a specialization of the class for the type 'float':
template <>
class C <float>
{
public:
C (float f) : d_f(f) {};
~C () = default;
void print ()
{
std::cout << "float: " << d_f << std::endl;
}
private:
float d_f;
};
and since the definitions are in the .cpp file I must explicitly instantiate all the specializations that I will be using. So I have:
template class C<int>;
template class C<float>;
The driver for my test looks like this in test.cpp:
#include "temp.hpp"
int main()
{
int i = 1;
C<int> c_int(i);
float f = 1.2;
C<float> c_float(f);
c_int.print();
c_float.print();
}
Upon compiling and linking this I get error:
test.cpp: undefined reference to `C<float>::print()'
The object code for the C< int > is properly generated. I can see it using nm:
nm -C temp.o
...
0000000000000000 W C<int>::print()
0000000000000000 W C<int>::C(int)
0000000000000000 W C<int>::C(int)
...
As I mentioned earlier, this is consistent with gcc and clang so I'm assuming there is some language rule I don't understand here.
Note that if I add a usage of the print() method in file temp.cpp, then the code is generated, but that is silly and in my real code would be impossible. For this simple test case it would look like:
void foo ()
{
C<float> s(1.3);
s.print();
}
In the real code which motivated this little test my template has 3 template arguments which combine to expand into about 30 permutations of the code. There are one or two of those for which I need a specialization which does something different, but the other 28 I can leave alone.
Any pointers on where I've gone wrong or a language reference for why the explicit instantiation of should not generate code are greatly appreciated. I've spent 1/2 a day reading all the other stackoverflow posts on explicit instantiation and believe I am using it correctly.
From [temp.expl.spec]:
We're explicitly specializing
C
in temp.cpp, but in test.cpp, it is not declared before it is used. Thus, your code is ill-formed, no diagnostic required. You'll have to simply move the declaration ofC<float>
into temp.hppAlways be careful with explicit specializations. The standard takes them very seriously: