不同dll中的C++模板特化会产生链接器错误

jos*_*efx 1 c++ dll templates dllimport visual-studio-2010

我有一个第三方dll包含一个具有多个特化的模板类.我在Linux上有自己的专业,试图编译一个Windows DLL然而导致链接器错误.

我试了一下,发现模板头上的dllimport规范可能是原因,删除它会解决我的问题.但是我不想修改或复制标题,因为它可能会随着第三方库的每次更新而中断.

这是一个重现我的问题的最小例子

test.h - dll/so header:

#ifdef _WIN32
#ifdef EXPORT
#    define LIB_EXPORT __declspec(dllexport)
#else
#    define LIB_EXPORT __declspec(dllimport)
#endif
#else
#    define LIB_EXPORT
#endif

template <typename A> class LIB_EXPORT Foobar
{
   public:
      virtual void helloWorld(){}
      virtual ~Foobar(){}
}; 
Run Code Online (Sandbox Code Playgroud)

test.cpp - dll/so impl:

#define EXPORT
#include "test.h" 

template class __declspec(dllexport) Foobar<int>;
Run Code Online (Sandbox Code Playgroud)

main.cpp - 示例程序:

#include "test.h"
//explicit instanciation - does not help
template class __declspec(dllexport) Foobar<char>;
int main(int argc, char** argv)
{
    Foobar<char> a;
    a.helloWorld();
}
Run Code Online (Sandbox Code Playgroud)

有没有一种干净的方法可以在我的可执行文件中完整地实例化Foobar?

使用的编译器:Visual Studio 2010,g ++ mingw w64 4.9.1

Ben*_*Ben 6

我知道你说你不想修改标题因为它可能会破坏第三方库更新,但是模板定义的标题没有正确设置.希望您可以让您的供应商修改他们的标题以更加友好的导入/导出.

目标:

在dll /中定义(导出)模板特化,然后使用(导入)该特化到您的exe.

test.h


我们希望只导入或导出每个模板的专业化,所以我们从类别中删除LIB_EXPORT.

template <typename A> class Foobar {
...
}
Run Code Online (Sandbox Code Playgroud)

但我们确实要导入/导出模板的特定专业化.我们将转发声明特化,然后在您希望它驻留的编译单元中显式实例化它.

由于您还使用gcc构建,因此您需要使用'extern'关键字.Visual Studio 2010不会为模板实现它.

#ifdef _WIN32
#    define TEMPLATE_EXTERN
#ifdef EXPORT
#    define LIB_EXPORT __declspec(dllexport)
#else
#    define LIB_EXPORT __declspec(dllimport)
#endif
#else
#    define TEMPLATE_EXTERN extern
#    define LIB_EXPORT
#endif
Run Code Online (Sandbox Code Playgroud)

最终的前瞻性声明如下

TEMPLATE_EXTERN template class LIB_EXPORT Foobar<int>;
Run Code Online (Sandbox Code Playgroud)

TEST.CPP


我们在这里明确地实例化了模板类,因为我们在头文件中的努力已经关闭了编译器的自动实例化功能.

#define EXPORT
#include "test.h" 

template class Foobar<int>;
Run Code Online (Sandbox Code Playgroud)

main.cpp中


标头的默认状态是使用任何非int类型隐式实例化Foobar类.int专门化在gcc上被标记为'export',在win32上被标记为__declspec(dllimport).因此,您可以在任何地方进行其他专业化.

#include "test.h"

// explicit instantiation
template class Foobar<char>;

int main(int argc, char** argv)
{
    Foobar<char> a;
    a.helloWorld();
}
Run Code Online (Sandbox Code Playgroud)