模板,静态变量和dll

时间:2018-09-09 09:06:46

标签: c++ templates static visual-studio-2017 c++17

我正在尝试导出定义中带有静态变量的功能模板。

.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();
}

我希望.dll和.exe进行的调用引用相同的“ _instance”对象。我知道我可以通过在.cpp中定义静态变量来做到这一点。但是在这种情况下,我正在处理模板,因此有点卡住。

编辑: 发生什么事的例子..

.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)
}

1 个答案:

答案 0 :(得分:0)

每个带有API__declspec(dllexport)__declspec(dllimport))的模板都需要分开标记,并且不能将其内联到类代码中。

Foo.h文件为:

#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();
};

请注意,尽管所有Get()类也都用API进行了标记,但我们仍将FooAPI分开(事实上,类标记对模板功能没有影响,因此需要它标记为单独)。并且此处没有实现Get-导出的函数无论如何都不能内联。

因此dll代码(Foo.cpp)必须如下所示:

#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;
}

请注意,我们再次在函数体的实现中显式使用API__declspec(dllexport))。这一点非常重要-如果您在此处跳过API,但编译器不会警告您,但如果不这样做,则Get将不会导出。

确保此时所有正确-复制__pragma(message("__imp_" __FUNCDNAME__)) (看起来像__imp_??$Get@H@Foo@@SAAEAHXZ)产生的字符串并精确搜索 (符号到符号)此字符串在创建的 .lib 文件中-构建dll之后。如果存在-一切正常,否则无法继续(使用exe)

并在exe中:

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

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