在 DLL 接口中导出包含相同 class 的 STL class 成员

Export a STL class member containing the same class in a DLL interface

假设我有一个 class 在 STL 容器中引用自身:

class __declspec(dllexport) Widget {
protected:
    std::vector<Widget *> children;
}

如果我说 intvector,那么在 class 定义之前我可以有以下内容:

template class __declspec(dllexport) std::vector<int>;

这应该会起作用。但是,如果 class 尚未定义,我该怎么做呢?转发声明 class:

class Widget;
template class __declspec(dllexport) std::vector<Widget *>;

没有消除我从 MSVC 收到的警告;

warning C4251: 'Widget::children' : class 'std::vector<Widget *,std::allocator<_Ty>>' needs to have dll-interface to be used by clients of class 'Widget'

我相信警告中的信息本身在某种程度上是相关的,但我不确定具体如何进行。

警告本身确实相关。其中提到的头文件安装在与我正在处理的目录不同的目录中,因此没有看到我的更改。修复警告的正确方法是:

class Widget;
template class __declspec(dllexport) std::vector<Widget *>;

在 class 定义之前。

取自 here,这些错误系列本质上是噪音;

C4251 is essentially noise and can be silenced
- Stephan T. Lavavej (one of the maintainer's of Micrsoft's C++ library).

只要编译器选项在整个项目中保持一致,只需消除此警告就可以了。

作为更全面的替代方案,您可以查看 pimpl pattern 并从 class 定义中删除 std::vector,因此它会不需要从dll导出。

class __declspec(dllexport) Widget {
protected:
    struct Pimpl;
    Pimpl* pimpl_;
}

// in the cpp compiled into the dll
struct Widget::Pimpl {
    // ...
    std::vector<Widget*> children;
    // ...
}

MSDN has a nice article on this 作为 C++11 新特性介绍的一部分。

通常,在 dll interface 中不使用 std class 会更容易,尤其是在需要互操作性时。