【发布时间】:2011-10-21 11:40:20
【问题描述】:
在 DLL 中,我有一个带有模板基类的导出非模板类。这个模板基类有一个静态成员变量。我在一个可执行文件中使用静态基成员,该文件通过导出的非模板类链接到 DLL。
在许多情况下,我会收到未解决的外部符号或有关不一致链接的投诉。我找到了一种可行的方案,但它似乎很笨拙,所以我想知道是否有更好的方法,以及这种更好的方法是否也可能指向 VS2010 SP1 的 C++ 编译器/链接器的缺陷。
这是我可以提取的 DLL 的最小场景 - 我认为我不能在不破坏场景的情况下删除这里的任何内容。
// Header file
template<typename T>
class _MYDLL_EXPORTS TBaseClass
{
public:
static const double g_initial_value;
};
class _MYDLL_EXPORTS MyClass : public TBaseClass<MyClass>
{
};
// Kludge: use this code only when building the DLL, not when including
// from the DLL's client
#ifdef _MYDLL
template<typename T>
const double TBaseClass<T>::g_initial_value = 1e-5;
#endif
// CPP file
#include "header.h"
// Explicit instantiation of the template for the correct parameter.
template class TBaseClass<MyClass>;
然后是DLL的用户
#include <header.h>
#include <iostream>
int main(void) {
MyClass c;
std::cout << c.g_initial_value;
return 0;
}
【问题讨论】:
-
您可以用 C++ 编写 DLL,但导出的接口应始终与 C 兼容。其他任何事情都是自找麻烦。您的设计很脆弱,并且可能会因库和客户端之间编译器选项的最细微差异而中断。
-
@Ben Voigt - 虽然我同意您关于通用库的观点,但在这种情况下,库和客户端都在我的完全控制之下,并且它们保证使用相同的构建编译器和设置通过各种机制。 maco _MYDLL_EXPORTS 根据包含的位置扩展为 _declspec(dllexport) 或 _declspec(dllimport) - 根据我的经验,这是一种非常常见的模式,适用于较大的原生 C++ win32 应用程序。
-
您的解决方案已经正确。如果是模板,链接器会自动消除重复项。此外,VC++ 链接器可能更喜欢 TBaseClass::g_initial_value 的 dllimport 版本,但事实并非如此。通过使用 #ifdef _MYDLL 你可以帮助它。您可以向 MS Connect 提交错误,但他们倾向于关闭诸如“无法修复”之类的问题。
标签: c++ windows visual-studio-2010 templates