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’).
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.
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")
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!!