Templates & DLLs

I am trying to create a dll that contains templates where the templates should be compiled (rather than in the header file). However, I am getting the following linker error:

error LNK2019: unresolved external symbol "__declspec(dllimport) long __cdecl AddT(long,long)" (__imp_?AddT@@YAJJJ@Z) referenced in function _main

The code is shown below. “Add” works fine but “AddT” does not. I understand that I can’t export the template itself. Hence I just declare and define the template in my dll and the instantiate one with a particular type (here just ‘long’).

Dumpbin on the lib gives me the following:

??$AddT@J@@YAJJJ@Z (long __cdecl AddT<long>(long,long))
?Add@@YAHHH@Z (int __cdecl Add(int,int))

//MyDll.cpp
__declspec(dllexport) int Add(int a, int b);
__declspec(dllexport) int Add(int a, int b) { return a+b; }

template<typename T> T AddT(T a, T b);
template<typename T> T AddT(T a, T b) { return a+b; }

template __declspec(dllexport) long AddT<long>(long a, long b);

//DllConsumer.cpp
__declspec(dllimport) int Add(int a, int b);
__declspec(dllimport) long AddT(long a, long b);

int main(int argc, char* argv[]) {
int i = Add(1, 2); //works
long l = AddT(3, 4); //LNK2019
return 0;
}

DllConsumer.cpp is incorrect. It tries to import a non-template function from a library that exports a template function. Look at the symbols.
You're trying to import ?AddT@@YAJJJ@Z.
The DLL exports ??$AddT@J@@YAJJJ@Z.

PS: Wouldn't it be easier to just export all the overloads? Templates are not really suited to do this.
Last edited on
Good point that the signature doesn't match. I guess the question is why it doesn't match. I tried many different variations (adding 'template' to the import in DllConsumer.cpp, adding export to the template in MyDll.cpp, etc). I also searched hours on the internet but couldn't resolve this (most examples use classes which use a bit different explicit instantiation).

I am afraid I don't understand what you mean with "export all the overloads". FYI, I am using templates because I need these functions for a fixed but reasonably large number (~half dozen) of types. So I chose templates with the goal of just making the types available that I need.
_declspec(dllimport) template<typename T> T AddT(T a, T b); should do it.

I am using templates because I need these functions for a fixed but reasonably large number (~half dozen) of types.
You're going to have to explicitly instantiate the template for each of those types anyway. You're not actually gaining anything. You could do
1
2
3
4
5
6
7
8
9
10
11
12
//The template is not exported. It's only used to implement the overloads.
 template<typename T> T AddT(T a, T b) { return a+b; }

__declspec(dllexport) long Add(long a, long b){
    return AddT(a, b);
}

__declspec(dllexport) long Add(double a, double b){
    return AddT(a, b);
}

//etc. 
This has the advantage that the compiler can see which types are supported by Add() and give more useful error. For example, in your code this call would be accepted by the compiler, but it would fail to link due to an undefined reference: AddT((std::string)"a", (std::string)"b")
Last edited on
helios, that is perfect. I ended up doing what you suggested. Actually, it's exactly what I wanted. It allows me to use templates in the background while it makes it very clear to the user which datatypes are supported. Thank you!!
Topic archived. No new replies allowed.