Reputation: 55
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
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