症状:
在DLL中定义一个模板类并用__declspec(dllexport)定义。
1: template<typename T, int d>
2: class DLLExportExportMacro vectortemp
3: {
4: public:
5:
6: vector m_Vector;
7:
8: public:
9: vectortemp(vector v):m_Vector(d)
10: {
11: if (v.size() == d)
12: {
13: m_Vector = v;
14: }
15: else
16: throw invalid_argument("Vector size does not match.");
17: }
18:
19: vectortemp(T v[]):m_Vector(d)
20: {
21: if (sizeof(v)/sizeof(T) == d)
22: {
23: vector::iterator iter = m_Vector.begin();
24: int i = 0;
25: while (iter != m_Vector.end())
26: {
27: *iter++ = v[i];
28: }
29: }
30: else
31: throw invalid_argument("Vector size does not match.");
32:
33: }
34:
35: vectortemp():m_Vector(d)
36: {
37: vector::iterator iter = m_Vector.begin();
38: while (iter != m_Vector.end())
39: {
40: *iter = 0;
41: }
42: }
43:
44: const T &operator[](int index) const
45: {
46: return m_Vector[index];
47: }
48:
49: T &operator[](int index)
50: {
51: return m_Vector[index];
52: }
53: };
警告提示出现在line 6。意思说vector需要用dll接口(__declspec(dllimport))从而使其被客户类vectortemp使用。__declspec(dllimport)用于所有需要从dll导入的对象,包括变量,函数,类等。而且必须用在定义前面。如果vectortemp中使用的不是一个模板类vector<>,这里会报错。因为头文件vector里只是vector类的声明。在vector实例化时,编译器会生成一份和头文件中一样的代码,一份本地类定义,当然加上模板参数,比如vector。所以用模板类不会出错,但编译器会友好地产生一个警告。警告不会影响程序运行,可以不用理睬。但是随着使用vectortemp的增加,警告会越来越多。这个确实很丑陋!解决方法有两个:直接用下面这个命令关闭警告。
1: #pragma warning( disable: 4251 )
第一个方法还是丑陋了点,而且也不能了解内幕。我们需要一个显示地实例化模板,从而得到模板的一个定义。对一个非stl模板,可以这样:
1: template class DLLExportExportMacro SomeTemplate<int>;
2: SomeTemplate<int> y;
对于stl模板,如果只是相应的改成
1: template class DLLExportExportMacro std::vector<int>;
2: std::vector<int> y;
你会得到这个:
1: warning C4251: 'std::_Vector_val<_Ty,_Alloc>::_Alval' :
2: class std::allocator<_Ty>' needs to have dll-interface to be used by clients of class 'std::_Vector_val<_Ty,_Alloc>'
因为stl::vector的实际定义是"std::vector >"。所以还要import std::allocator。
1: template class DLLExportExportMacro std::allocator<int>;
2: template class DLLExportExportMacro std::vector<int>;
3: std::allocator<int> >;
方法二:导致链接错误
如果同时有两个DLL库用用显示实例方法导出vector,会导致vector的重定义。唯一的解决办法就是用#pragma warning( disable: 4251屏蔽警告。