在共享对象/ DLL中使用模板化的类和函数

Tra*_*kel 6 c++ dll templates visual-c++

我正在开发一个跨越许多共享库的相当大的项目.我们也非常依赖STL,Boost和我们自己的模板类和函数.许多导出的类包含模板成员,导出的函数包含模板参数.

这是我如何进行库导出的精简示例:

#if defined(_MSC_VER) && defined(_DLL)
    //    Microsoft 
    #define EXPORT __declspec(dllexport)
    #define IMPORT __declspec(dllimport)
#elif defined(_GCC)
    //    GCC
    #define EXPORT __attribute__((visibility("default")))
    #define IMPORT
#else
    //    do nothing and hope for the best at link time
    #define EXPORT
    #define IMPORT
#endif

#ifdef _CORE_COMPILATION
#define PUBLIC_CORE EXPORT
#define EXTERNAL_CORE
#else
#define PUBLIC_CORE IMPORT
#define EXTERNAL_CORE extern
#endif

#include <deque>

//    force exporting of templates
EXTERNAL_CORE template class PUBLIC_CORE std::allocator<int>;
EXTERNAL_CORE template class PUBLIC_CORE std::deque<int, std::allocator<int> >;

class PUBLIC_CORE MyObject
{
private:
    std::deque<int> m_deque;
};
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是当我在Visual Studio中编译时(2008年和2010年),我收到以下警告:

警告C4251:'std :: _ Deque_val <_Ty,_Alloc> :: _ Almap':类'std :: allocator <_Ty>'需要让dll-interface使用类'std :: _ Deque_val <_Ty,_Alloc的客户端>"

这似乎意味着我没有出口std::allocator<int>,我有.并不是我的出口不正确,因为不包括

EXTERNAL_CORE template class PUBLIC_CORE std::allocator<int>;
EXTERNAL_CORE template class PUBLIC_CORE std::deque<int, std::allocator<int> >;
Run Code Online (Sandbox Code Playgroud)

产生警告:

警告C4251:'MyObject :: m_deque':类'std :: deque <_Ty>'需要让dll接口被'MyObject'类的客户端使用

我能想到的唯一一件事是_Ty关于std::allocator正在谈论的警告不知何故int,但我似乎无法找到任何迹象,否则,因为一个std::deque<int>逻辑上会分配一个std::allocator<int>.

一个消费应用程序可以很好地使用该类,但我有一种直觉,不应忽略此警告.在Linux中使用g ++进行编译时,不会发出任何错误(尽管这并不意味着它正常工作).g ++会自动执行MSVC无法做到的事情吗?我一直瞄准Linux上的GCC,OSX上的LLVM和Windows上的MSVC,但是我可能会转向MinGW进行Windows开发,因此放弃MSVC并不是不可能的(如果这被证明是太大的不便) .

xto*_*ofl 3

您可能知道,导出文件中的模板实际上是编译器的“填写您认为必要的任何内容的权限”。

这意味着,如果您使用编译器 A 编译头文件,它可能会实例化deque<int>与编译器 B 完全不同的头文件。其中一些成员的顺序可能会发生变化,甚至某些成员变量的实际类型也会发生变化。

这就是编译器警告您的内容。

编辑:在解释中添加一些后果

因此,您的共享库只有在由同一编译器编译时才能很好地协同工作。如果您希望它们一起工作,您可以确保所有客户端代码“看到”相同的声明(通过使用相同的 stl 实现),或者退出向 API 添加模板。