跨DLL的c++成员函数显式模板实例化

C++ member function explicit template instantiation across DLL

本文关键字:实例化 函数 DLL c++ 成员      更新时间:2023-10-16

我在Windows 8.1 Update 1上使用Visual Studio 2013C++中创建DLL。有一个名为XMLData的类,它有一个名为getAttribute的公共成员函数。

XMLData.h

namespace DDGL
{
    class DLL_EXPORTED XMLData
    {
       ...
       // const char* is used to avoid problems with trying to pass an
       // std::string over DLL boundaries
       template <typename Type> Type getAttribute (const char* attribute) const;
       ...
    };
}

在DLL内部,每次使用都像您期望的那样实例化并且工作良好。

然而,在一个应用程序中,我当然会得到未定义的引用,<typename Type>在DLL中没有使用。

因此,我尝试使用显式模板实例化(我宁愿不把实现放在header中,如果有的话,作为学习练习):

XMLData.cpp

namespace DDGL
{
    ...
    // getAttribute definition
    ...
    template float XMLData::getAttribute(const char* attribute) const;
    ...
}

然而,我仍然在使用DLL的应用程序中得到一个未解决的外部:

error LNK2019: unresolved external symbol "public: float __thiscall DDGL::XMLData::getAttribute<float>(char const *)const " (??$getAttribute@M@XMLData@DDGL@@QBEMPBD@Z) referenced in function "class std::shared_ptr<class DDGL::IGameObject> __cdecl SimpleExplodingRocketDeserialiser(class DDGL::XMLData)" (?SimpleExplodingRocketDeserialiser@@YA?AV?$shared_ptr@VIGameObject@DDGL@@@std@@VXMLData@DDGL@@@Z)

DLL_EXPORTED

#ifdef DDGL_DLL_BUILDING
    #define DLL_EXPORTED __declspec(dllexport)
#else
    #define DLL_EXPORTED __declspec(dllimport)
#endif

我哪里错了?

虽然@OMGtechy解决方案有效,但我认为这是多余的。为模板声明和模板定义指定DLL_EXPORTED就足够了。

头文件:

namespace DDGL
{
    class DLL_EXPORTED XMLData
    {
       template <typename Type> DLL_EXPORTED Type getAttribute (const char* attribute) const;
    };
}

在.cpp文件中定义函数:

namespace DDGL
{
    template<> DLL_EXPORTED float XMLData::getAttribute(const char* attribute) const {
        // Function body goes here
    }
}

在msvc++ 2017上测试。

一些想法:我认为这将是合乎逻辑的,如果DLL_EXPORTED类定义工作在其模板方法。非模板化方法不需要在每个方法上再次设置DLL_EXPORTED。模板方法有什么不同?我不确定。

问题是,虽然我确实正确地显式实例化了模板,但我并没有为每个实例化导出符号。

解决方法如下:

namespace DDGL
{
    class DLL_EXPORTED XMLData
    {
       ...
       // const char* is used to avoid problems with trying to pass an
       // std::string over DLL boundaries
       template <typename Type> Type getAttribute (const char* attribute) const;
       ...
    };
    DLL_TEMPLATE_CLASS_MEMBER float XMLData::getAttribute(const char* attribute) const;
}

其中DLL_TEMPLATE_CLASS_MEMBER定义为:

#ifdef DDGL_DLL_BUILDING
    #define DLL_TEMPLATE_CLASS_MEMBER template DLL_EXPORTED
#else
    #define DLL_TEMPLATE_CLASS_MEMBER extern template DLL_EXPORTED
#endif

正确地导出了用于显式模板实例化的符号,并允许我在DLL外使用它们。