我正在使用DLL
上的C++
在Visual Studio 2013
中创建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内部,每次使用都会按照您的预期进行实例化,并且工作正常。
但是,在应用程序中,我当然会获得未在DLL中使用的<typename Type>
的未定义引用。
所以,我尝试使用显式模板实例化(我宁愿不将实现放在头文件中,以便进行学习练习):
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
我哪里错了?
答案 0 :(得分: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外部使用它们。
答案 1 :(得分: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
。那么模板方法有什么不同呢?我不确定。