47

I'm trying to link to a shared library with a template class, but it is giving me "undefined symbols" errors. I've condensed the problem to about 20 lines of code.

shared.h

template <class Type> class myclass {
  Type x;
public:
  myclass() { x=0; }
  void setx(Type y);
  Type  getx();
};

shared.cpp

#include "shared.h"
template <class Type> void myclass<Type>::setx(Type y) { x = y; }
template <class Type> Type myclass<Type>::getx() { return x; }

main.cpp

#include <iostream>
#include "shared.h"
using namespace std;

int main(int argc, char *argv[]) {
   myclass<int> m;
   cout << m.getx() << endl;
   m.setx(10);
   cout << m.getx() << endl;
   return 0;
}

This is how I compile the library:

g++ -fPIC -c shared.cpp -o shared.o
g++ -dynamiclib -Wl,-dylib_install_name -Wl,libshared.dylib -o libshared.dylib shared.o

And the main program:

g++ -c main.cpp
g++ -o main  main.o -L. -lshared

Only to get the following errors:

Undefined symbols:
"myclass<int>::getx()", referenced from:
  _main in main.o
  _main in main.o
"myclass<int>::setx(int)", referenced from:
  _main in main.o

If I remove the 'template' stuff in shared.h/cpp, and replace them with just 'int', everything works fine. Also, if I just copy&paste the template class code right into main.cpp, and don't link to the shared library, everything works as well.

How can I get a template class like this to work through a shared library?

I'm using MacOS 10.5 with GCC 4.0.1.

nolk
  • 696
  • 1
  • 6
  • 10
  • Duplicate: http://stackoverflow.com/questions/999358/undefined-symbols-linker-error-with-simple-template-class/999383#999383 – Todd Gardner Jun 20 '09 at 21:48

4 Answers4

51

In addition to the other answers, you can explicitly instantiate template classes. This is only useful if you know beforehand what types the template parameters may assume. You instantiate the template with all these types in the library.

For your example to compile, just add the following to the end of shared.cpp:

// Instantiate myclass for the supported template type parameters
template class myclass<int>;
template class myclass<long>;

This instantiates the template with Type=int and places the instantiated code in the shared library. Add as many explicit instantiations as you need, for all the types you need.

Again, if you want to be able to instantiate the template with any arbitrary Type parameter, then you must add the definitions to the header file, so that the compiler knows the source code of the template when instantiating it in other compilation units.

Juliano
  • 39,173
  • 13
  • 67
  • 73
  • 3
    This is exactly what I was looking for. Thank you so much! For reference to other people with the same problem: Add the template instantiation lines at the END of the shared.cpp file. – nolk Jun 20 '09 at 22:49
  • 1
    That's great, but what if I have _two source files_, not one as the OP does? Where should I add these lines then? – ForceBru Jan 06 '16 at 16:13
  • @ForceBru: In either one. I suggest the source file that corresponds to the header file which defines the template. – Cookie Mar 04 '16 at 11:12
  • "Massive catcha solved - use 'template class myclass' in template namespace CPP to fix missing symbols in DLL/SO. Compiler fails to include symbols in objects - unclear on templates' workings. Thanks!" – boardkeystown Apr 22 '23 at 02:38
20

Template function definitions must reside in header files. Move the definitions from shared.cpp to shared.h.

So, you can't compile this to a shared library and then link to it. It just doesn't work like that.

rlbond
  • 65,341
  • 56
  • 178
  • 228
  • 2
    So it's impossible to have a shared library with templates? – nolk Jun 20 '09 at 22:00
  • 2
    On the contrary, it is ridiculously easy. Just put it in a header file, and share that. You don't even need a compiler then ;) Templates don't get compiled until they are instantiated, so if you put a template in a .cpp file and compile that as a shared library, the template code is simply removed. The template definition has to be visible to the user. – jalf Jun 20 '09 at 22:23
  • Are you absolutely certain ? Because I'm currently working with a shared library that instantiates templates during its compilation. The code is invisible by the user, yet it can be used. Compilation issues might arise when you mix specializations that needs generation and others that are already generated. But except for that it does work fine. Tested with g++ and msvc. – Michael Feb 02 '13 at 11:00
  • 1
    Exception to the rule: It _is_ possible to define a template function in a `.cpp` file—so long as _only_ that `.cpp` file instantiates the template. – Craig M. Brandenburg Apr 25 '14 at 17:46
6

You need to include the implementation of the template classes in the header files as well. This is a constraint of templates in C++. So either include shared.cpp from main (#include ) or just move the code from shared.cpp in shared.h

Cătălin Pitiș
  • 14,123
  • 2
  • 39
  • 62
2

The compiler has to see all the code for a template, so it can generate the appropriate code for the actual type you want to use. So you should place all the code in your .h. file.

nos
  • 379
  • 2
  • 6