如何在stl模板中使用导出的类(__declspec(dllexport))?

时间:2010-11-23 06:47:01

标签: c++ templates dllexport

我正在使用导出的课程

class __declspec(dllexport) myclass  
{  
private:  
template __declspec(dllexport) class std::map<myclass*,int>;    
std::map<myclass*,int>m_map;  
//something  
};    

当我这样做时,我得到一个警告C4251说m_map:class'std :: map&lt; _Kty,_Ty&gt;'需要让myclass类的客户端使用dll接口 关于我如何解决这个问题的任何想法? 阿图尔

3 个答案:

答案 0 :(得分:6)

您不应该将__declspec(dllexport)用于使用您的DLL将使用的代码的头文件中,因为它们需要使用__declspec(dllimport)。

因此,如果设置了特定的其他定义,则应创建一个使用dllexport的宏,如果不设置,则应创建dllimport。

在某个公共标题中:

#ifdef EXPORTING_FOO
#define FOO_API __declspec(dllexport)
#else
#define FOO_API __declspec(dllimport)
#endif

您可以实例化模板:

extern template class FOO_API Templ<MyClass, int >;

在一个包含的标题内。注意这里的extern。 在一个编译单元内声明相同但没有extern且没有FOO_API,因此:

template class Templ<MyClass, int >;

这意味着使用您的库的代码不会实例化模板,但会使用您库中的模板。当模板具有虚拟成员时,这尤其有用。

如果模板是标准库或boost中的模板,则使用您的模板的代码必须使用与您相同的版本,否则可能会出现严重问题。

鉴于在您自己的示例中,它出现在私有区域中,建议您将其重构为库的接口。理想情况下,您的库只应公开除前向声明之外的公共方法和成员。私有拷贝构造函数和赋值是为了使一个类不可复制和不可赋值是可以的 - 它们实际上并不是它们属于你的类接口的实现的一部分(你说你不能复制或分配它们) )。

答案 1 :(得分:2)

您无法导出包含未导出成员的类。一种可能的解决方案是使用Pimpl习语。使用Pimpl,用户不知道该类的成员。因此不需要导出stl类。有关pimpl的进一步阅读,请查看以下内容: http://c2.com/cgi/wiki?PimplIdiomhttp://www.gamedev.net/reference/articles/article1794.asp

示例:

myclass.h:

class __declspec(dllexport) myclass
{
public:
    myclass();
    virtual ~myclass();
private:
    myclass(const myclass& other) {}
    myclass& operator=(const myclass& rhs) {return *this;}
    myclassImpl* m_Pimpl;
};

myclass.cpp:

#include "myclass.h"
#include "myclassImpl.h"


myclass::myclass()
    :m_Pimpl(new myclassImpl())
{}

myclass::~myclass() {
    delete m_Pimpl;
}

myclassImpl.h:

class myclassImpl {
private:
    std::map<myclass*,int>m_map;
};

答案 2 :(得分:2)

从未尝试过,但此链接似乎正在调查此问题: http://support.microsoft.com/kb/168958