C++ template specialization in different dll produces linker errors
Asked Answered
W

1

3

I have a third party dll that contains a template class with several specializations. I have my own specialization on Linux, trying to compile a windows dll however results in linker errors.

I tried around a bit and found out that the dllimport specification on the template header may be the cause and removing it would fix my problem. However I don't want to modify or copy the header since it could break with every update to the third party library.

Here is a minimal example to reproduce my problem

test.h - dll/so header:

#ifdef _WIN32
#ifdef EXPORT
#    define LIB_EXPORT __declspec(dllexport)
#else
#    define LIB_EXPORT __declspec(dllimport)
#endif
#else
#    define LIB_EXPORT
#endif

template <typename A> class LIB_EXPORT Foobar
{
   public:
      virtual void helloWorld(){}
      virtual ~Foobar(){}
}; 

test.cpp - dll/so impl:

#define EXPORT
#include "test.h" 

template class __declspec(dllexport) Foobar<int>;

main.cpp - example program:

#include "test.h"
//explicit instanciation - does not help
template class __declspec(dllexport) Foobar<char>;
int main(int argc, char** argv)
{
    Foobar<char> a;
    a.helloWorld();
}

Is there a clean way to get a complete instantiation of Foobar in my executable ?

Compilers used: Visual Studio 2010, g++ mingw w64 4.9.1

Wanderlust answered 23/11, 2014 at 16:1 Comment(0)
M
9

I know you said that you dont want to modify the header since it could break the third party library updates, but the header that the template is defined in is not set up correctly. Hopefully you can get your vendor to modify their headers to be more import/export friendly.

The goal:

Define (export) a template specialization in a dll/so and then use (import) that specialization to your exe.

test.h


We dont want to only import or export every specialization of the template, so we remove the LIB_EXPORT from the class.

template <typename A> class Foobar {
...
}

We do want to import/export a specific specialization of the template however. We will forward declare the specialization and then explicitly instantiate it later in the compilation unit you want it to reside in.

Since you are also building with gcc, you will want to make use of the 'extern' keyword. Visual Studio 2010 does not implement it for templates.

#ifdef _WIN32
#    define TEMPLATE_EXTERN
#ifdef EXPORT
#    define LIB_EXPORT __declspec(dllexport)
#else
#    define LIB_EXPORT __declspec(dllimport)
#endif
#else
#    define TEMPLATE_EXTERN extern
#    define LIB_EXPORT
#endif

The final forward declaration looks like

TEMPLATE_EXTERN template class LIB_EXPORT Foobar<int>;

test.cpp


We explicitly instantiate the template class here since our efforts in the header file have turned off the automatic instantiation features of the compiler.

#define EXPORT
#include "test.h" 

template class Foobar<int>;

main.cpp


The default state of the headers is to implicitly instantiate the Foobar class with any type that is not int. The int specialization has been specifically tagged as 'export' on gcc and __declspec(dllimport) on win32. So you are able to make other specializations wherever you wish.

#include "test.h"

// explicit instantiation
template class Foobar<char>;

int main(int argc, char** argv)
{
    Foobar<char> a;
    a.helloWorld();
}
Matchbox answered 24/11, 2014 at 1:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.