【问题标题】:C++ template specialization in different dll produces linker errors不同 dll 中的 C++ 模板特化会产生链接器错误
【发布时间】:2015-01-21 08:19:40
【问题描述】:

我有一个第三方 dll,其中包含一个具有多个专业化的模板类。我在 Linux 上有自己的专长,尝试编译 windows dll 但会导致链接器错误。

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

这是重现我的问题的最小示例

test.h - dll/so 头文件:

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

test.cpp - dll/so impl:

#define EXPORT
#include "test.h" 

template class __declspec(dllexport) Foobar<int>;

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

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

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

【问题讨论】:

    标签: c++ visual-studio-2010 templates dll dllimport


    【解决方案1】:

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

    目标:

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

    test.h


    我们只想导入或导出模板的每个特化,因此我们从类中删除了 LIB_EXPORT。

    template <typename A> class Foobar {
    ...
    }
    

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

    由于您也在使用 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
    

    最终的前向声明看起来像

    TEMPLATE_EXTERN template class LIB_EXPORT Foobar<int>;
    

    test.cpp


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

    #define EXPORT
    #include "test.h" 
    
    template class Foobar<int>;
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-19
      • 1970-01-01
      • 2012-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多