C++ Shared Library with Templates: Undefined symbols error

27,217

Solution 1

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.

Solution 2

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.

Solution 3

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

Solution 4

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.

Share:
27,217

Related videos on Youtube

nolk
Author by

nolk

Updated on September 27, 2020

Comments

  • nolk
    nolk over 3 years

    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
    nolk almost 15 years
    So it's impossible to have a shared library with templates?
  • josesuero
    josesuero almost 15 years
    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.
  • nolk
    nolk almost 15 years
    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.
  • Michael
    Michael over 11 years
    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.
  • Craig M. Brandenburg
    Craig M. Brandenburg about 10 years
    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.
  • ForceBru
    ForceBru over 8 years
    That's great, but what if I have two source files, not one as the OP does? Where should I add these lines then?
  • Cookie
    Cookie about 8 years
    @ForceBru: In either one. I suggest the source file that corresponds to the header file which defines the template.