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

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

最佳答案

您需要每个带有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,但我们还是用Foo标记了API(实际上,类标记对模板功能没有影响,因此需要将其标记为单独)。而且这里没有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),并在生成dll后在创建的.lib文件中精确搜索(符号到符号)。如果存在-一切正常,否则毫无意义(使用exe)

并在exe中:
#include "../foo_dll/foo.h"

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

关于c++ - 模板,静态和dll,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52242984/

10-11 22:54
查看更多