user3427783
user3427783

Reputation: 55

Template, statics and dll

I am trying to export a function template with a static variable in the definition.

.dll/Foo.h:

#ifdef _DLL
#define API __declspec(dllexport)   
#else  
#define API __declspec(dllimport)   
#endif  

class API Foo
{
  public:
  template<typename T>
  static T& Get()
  {
    static T _instance;
    return _instance;
  }

  static void Set();
}

I want the calls made by the .dll and .exe to refer to the same "_instance" object. I know I can do that by defining the static variable in the .cpp. But in this case i am dealing with templates so i am kind of stuck.

Edit: Example of what is happening..

.dll/Foo.cpp:

void Foo::Set()
{
   Foo::Get<int>() = 10;
}

.exe/main.cpp:

int main()
{
  auto & x = Foo::Get<int>();
  x = 3;
  std::cout << x; // 3
  Foo::Set();
  std::cout << x; // 3 (I want it to be 10)
}

Upvotes: 3

Views: 257

Answers (1)

RbMm
RbMm

Reputation: 33794

you need separate mark every template with API (__declspec(dllexport) or __declspec(dllimport)) and not inline it in class code.

Foo.h file is:

#ifdef _DLL
#define API __declspec(dllexport)   
#else  
#define API __declspec(dllimport)   
#endif  

class API Foo
{
public:
    template<typename T> 
    API static T& Get();

    static void Set();
};

note that we separate mark Get() with API despite all Foo class also marked with API (class mark have no effect on template function by fact, so need it mark separate). and no implementation of Get here - exported functions anyway can not be inline.

so dll code (Foo.cpp) must look like:

#include "foo.h"

template<typename T>    
API T& Foo::Get()
{
    __pragma(message("__imp_" __FUNCDNAME__)) // for debug
    static T _instance;
    return _instance;
}

void Foo::Set()
{
    Foo::Get<int>() = 10;
}

note we again explicitly use API (__declspec(dllexport)) in implementation of function body. this is critical important - compiler not warning you, if you skip API here, but without this - Get will be not exported.

for sure that at this point all correct - copy string produced by __pragma(message("__imp_" __FUNCDNAME__)) (it will be look like __imp_??$Get@H@Foo@@SAAEAHXZ) and search exactly (symbol to symbol) this string in created .lib file - after you build dll. if it exist - all ok, otherwise no sense continue (with exe)

and in exe :

#include "../foo_dll/foo.h"

Foo::Get<int>() = 3;
Foo::Set();
if (Foo::Get<int>() != 10)
{
    __debugbreak();
}

Upvotes: 1

Related Questions