代码之家  ›  专栏  ›  技术社区  ›  Travis Gockel

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

  •  6
  • Travis Gockel  · 技术社区  · 16 年前

    我正在从事一个规模相当大的项目,该项目跨越了许多共享库。我们还非常依赖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;
    };
    

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

    警告C4251: '标准::_Deque_val<_Ty,_Alloc>::_阿尔马普 具有要由使用的dll接口 '标准::_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> >;
    

    发出警告:

    警告C4251:“MyObject::m_deque”: 的客户端使用的dll接口

    我唯一能想到的就是 _Ty 关于 std::allocator 他所说的不知何故不是 int ,但我似乎找不到任何迹象表明情况并非如此,因为 std::deque<int> 逻辑上会分配一个 std::分配器<int> .

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

    1 回复  |  直到 16 年前
        1
  •  3
  •   xtofl Adam Rosenfield    16 年前

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

    这意味着,如果使用编译器编译头文件,它可能会实例化一个完全不同的头文件 deque<int> 而不是编译器B。某些成员的顺序可能会更改,例如,某些成员变量的实际类型可能会更改。

    这就是编译器警告你的原因。

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