2

我正在创建一个DLLin C++using Visual Studio 2013on Windows 8.1 Update 1。有一个名为的类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 中使用的未定义引用。

因此,我尝试使用显式模板实例化(如果有的话,我宁愿不将实现放在标题中,以便进行学习练习):

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

我哪里错了?

4

2 回答 2

1

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

解决方案是执行以下操作:

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 之外使用它们。

于 2014-05-21T09:36:13.613 回答
1

尽管@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在每个方法上再次使用。那么模板方法有什么不同呢?我不确定。

于 2017-06-10T10:30:39.993 回答