使用 MinGW-w64 从 DLL 导出具有体外定义的类模板

jac*_*cob 5 c++ templates mingw dllimport dllexport

当涉及类模板时,我在使用 MinGW-w64(基于 MSYS2 的 GCC 11.3.0)将一个简单的 Windows 可执行文件正确链接到一个简单的 DLL 时遇到问题。最小的再现器如下。

库的完整代码(library.cpp)是

template <class T> class __attribute__((dllexport)) TestClass
{
    public:
        void member() { __builtin_printf("member from library\n"); }
        void other_member();
};

template class __attribute__((dllexport)) TestClass<int>;

template <class T> void __attribute__((dllexport)) TestClass<T>::other_member () {}
Run Code Online (Sandbox Code Playgroud)

我用它来编译它

g++ -std=c++11 library.cpp -o library.dll -shared -Wl,--out-implib,library.dll.a -Wl,--output-def,library.def
Run Code Online (Sandbox Code Playgroud)

程序的完整代码(program.cpp)是

template <class T> class __attribute__((dllimport)) TestClass
{
    public:
        void member() { __builtin_printf("member from program\n"); }
        void other_member();
};

extern template class __attribute__((dllimport)) TestClass<int>;

int main (void)
{
    TestClass<int> test;
    test.member();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我用它来编译它

g++ -std=c++11 program.cpp library.dll.a -o program.exe
Run Code Online (Sandbox Code Playgroud)

程序与 DLL 的链接失败,并显示undefined reference to TestClass<int>::member(). 事实证明,链接失败可以通过两种方式解决:

  1. 程序中的extern模板语句被注释掉。然后编译器使用模板的本地版本,程序打印“member from program”。
  2. 的定义已从TestClass<T>::other_member中注释掉。然后程序正确链接到库中的 并打印“成员来自库”。TestClass<int>::member

我理解第一点,即避免使用外部模板并进行本地隐式实例化。当我通过优化编译代码时也会发生这种情况。

但第二点让我困惑。为什么 的体外定义会TestClass<T>::other_member破坏 的导出TestClass<T>::member

免责声明:我正在调试别人的程序,因此设计选择不是我的。

Vir*_*co_ 1

据我所知:
没有library.cpp类模板的(显式)实例化,也没有所述类的成员函数。

template class __attribute__((dllexport)) TestClass<int>;
Run Code Online (Sandbox Code Playgroud)

将是一个(显式的)“模板专业化前向声明”......(因为它当然会)。
长话短说,如果(这是一个大胆的假设)我是对的,你只需要{}在后面添加即可TestClass<int>“定义”类型。

回答:

为什么 TestClass::other_member 的体外定义会破坏 TestClass::member 的导出?

我更加没有信心了。但是为什么要定义 的特化成员函数呢TestClasstemplate到底需要吗?

cf:显式(完整)模板专业化