2

I'm experiencing a LNK2019 linker error when trying to reference a class with a explicitly instantiated function template into another Visual Studio 2013 project.

The explicit instantiations works inside the same project (project1). But as soon as I try to reference the function template in project1 from another project (project2), I get the LNK2019 error linker.

I am using the __cdecl calling convention (/Gd flag) in both projects.

Project 1:

//foo.h:
#define FOO_API __declspec(dllexport)

class FOO_API foo
{
public:
    //basic constructor and destructor declartions
    template <class U, class T>
    FOO_API void someFunc(U a, T b);
};

//foo.c:
#include "foo.h"

//basic constructor and destructor definitions
template<class U, class T>
void foo::someFunc(U a, T  b)
{
    // do something
}

template void foo::someFunc(int a, int b);
template void foo::someFunc(int a, short b);

//bar1.h:
class bar1
{
public:
    //basic constructor and destructor declarations
    void someOtherFunc();
};

//bar1.cpp:
#include "bar1.h"
#include "foo.h"
void bar1::someOtherFunc()
{
    int a = 1, b = 2;
    short c = 3;
    char d = 'd';

    foo * myFoo = new foo();

    myFoo->someFunc(a, b); // Works as expected, as <int, int> was explicity instantiated in foo.cpp
    myFoo->someFunc(a, c); // Works as expected, as <int, int> was explicity instantiated in foo.cpp
    //myFoo->someFunc(a, d); // Fails as expected, no explicit <int, char> instantiation in foo.cpp
}

Project 2:

//bar2.h
class bar2
{
public:
   //basic constructor and destructor declarations

   void someOtherFunc();
};

//bar2.cpp:
#include "bar2.h"
#include "..\project1\foo.h"

//basic constructor and destructor definitions
void bar2::someOtherFunc()
{
    int a = 1, b = 2;
    short c = 3;
    char d = 'd';

    foo * myFoo = new foo();

    myFoo->someFunc(a, b); // Doesn't work
    myFoo->someFunc(a, c); // Doesn't work
}

The error I get is:

1>------ Build started: Project: Project2, Configuration: Debug x64 ------
1>bar2.obj : error LNK2019: unresolved external symbol "public: void __cdecl foo::someFunc<int,int>(int,int)" (??$someFunc@HH@foo@@QEAAXHH@Z) referenced in function "public: void __cdecl bar2::someOtherFunc(void)" (?someOtherFunc@bar2@@QEAAXXZ)
1>bar2.obj : error LNK2019: unresolved external symbol "public: void __cdecl foo::someFunc<int,short>(int,short)" (??$someFunc@HF@foo@@QEAAXHF@Z) referenced in function "public: void __cdecl bar2::someOtherFunc(void)" (?someOtherFunc@bar2@@QEAAXXZ)
1>c:\Projects\ExplicitTemplateTest\x64\Debug\Project2.dll : fatal error LNK1120: 2 unresolved externals
James
  • 270
  • 1
  • 10
  • are both projects using the same function call convention (cdecl)? – steve Aug 23 '18 at 03:49
  • 1
    You need to export those specializations, as in `template void FOO_API foo::someFunc(int a, int b);` You can drop `FOO_API` from the template declaration - it doesn't do any good there; templates cannot be exported. – Igor Tandetnik Aug 23 '18 at 04:55
  • Updated the question with the calling convention used (both projects are using __cdecl). – James Aug 23 '18 at 15:37
  • @IgorTandetnik - Thank you! That worked! – James Aug 23 '18 at 15:38

1 Answers1

2

As IgorTandetnik pointed out, I had to add the FOO_API (__declspec(dllexport)) to the explicit template instantiations. As he also pointed out, there was no need to keep it on the declaration, so I removed it.

So, inside Project1/foo.c, I changed

template void foo::someFunc(int a, int b); 
template void foo::someFunc(int a, short b);

to:

template FOO_API void foo::someFunc(int a, int b);
template FOO_API void foo::someFunc(int a, short b);

and inside Project1/foo.h, I changed

FOO_API void someFunc(U a, T b);

to

void someFunc(U a, T b);
Evg
  • 25,259
  • 5
  • 41
  • 83
James
  • 270
  • 1
  • 10