vendredi 31 juillet 2015

gcc/clang not generating code for fully specialized template even with explicit instantiation

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 templatized class, 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 argc, char** argv)
{
  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 lanuguage 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 testcase 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.

Thanks

Aucun commentaire:

Enregistrer un commentaire