【问题标题】:Using Templated Classes and Functions in a Shared Object/DLL在共享对象/DLL 中使用模板化类和函数
【发布时间】:2011-01-07 18:49:38
【问题描述】:

我正在从事一个规模相当大的项目,该项目跨越许多共享库。我们也非常依赖 STL、Boost 和我们自己的模板类和函数。许多导出的类包含模板成员,导出的函数包含模板参数。

这是我如何进行库导出的简化示例:

#if defined(_MSC_VER) && defined(_DLL)
    //    Microsoft 
    #define EXPORT __declspec(dllexport)
    #define IMPORT __declspec(dllimport)
#elif defined(_GCC)
    //    GCC
    #define EXPORT __attribute__((visibility("default")))
    #define IMPORT
#else
    //    do nothing and hope for the best at link time
    #define EXPORT
    #define IMPORT
#endif

#ifdef _CORE_COMPILATION
#define PUBLIC_CORE EXPORT
#define EXTERNAL_CORE
#else
#define PUBLIC_CORE IMPORT
#define EXTERNAL_CORE extern
#endif

#include <deque>

//    force exporting of templates
EXTERNAL_CORE template class PUBLIC_CORE std::allocator<int>;
EXTERNAL_CORE template class PUBLIC_CORE std::deque<int, std::allocator<int> >;

class PUBLIC_CORE MyObject
{
private:
    std::deque<int> m_deque;
};

SO,我的问题是当我在 Visual Studio(2008 和 2010)中编译时,我收到以下警告:

警告 C4251: 'std::_Deque_val<_ty>::_Almap' : 类 'std::allocator<_ty>' 需要 有 dll 接口可供使用 类客户 'std::_Deque_val<_ty>'

这似乎暗示我没有导出std::allocator&lt;int&gt;,我有。而且这不是我的导出不正确,因为不包括

EXTERNAL_CORE template class PUBLIC_CORE std::allocator<int>;
EXTERNAL_CORE template class PUBLIC_CORE std::deque<int, std::allocator<int> >;

产生警告:

警告 C4251:“MyObject::m_deque”: 类 'std::deque<_ty>' 需要有 客户端使用的dll接口 类“我的对象”

我唯一能想到的是 _Ty 关于 std::allocator 的警告在某种程度上不是 int,但我似乎找不到任何迹象表明它会不是这样,因为std::deque&lt;int&gt; 将在逻辑上分配 std::allocator&lt;int&gt;

消费应用程序可以很好地使用该类,但我有一种直觉认为不应忽略此警告。在 Linux 中使用 g++ 进行编译时,不会发出任何错误(尽管这并不意味着它工作正常)。 g++ 是否会自动执行 MSVC 无法执行的操作?我一直针对 Linux 上的 GCC、OSX 上的 LLVM 和 Windows 上的 MSVC,但我可能会转向 MinGW 进行 Windows 开发,所以放弃 MSVC 并不是完全不可能的(如果这被证明是太大的不便) .

【问题讨论】:

标签: c++ visual-c++ dll templates


【解决方案1】:

您可能知道,导出文件中的模板实际上是编译器的“填写您认为必要的任何内容的权限”。

这意味着如果你用编译器 A 编译你的头文件,它可能会实例化一个与编译器 B 完全不同的deque&lt;int&gt;。一些成员的顺序可能会改变,对于一个,甚至是一些成员变量的实际类型。

这就是编译器警告你的原因。

编辑:在解释中添加一些后果

因此,您的共享库只有在由同一个编译器编译时才能很好地协同工作。如果您希望它们一起工作,您可以确保所有客户端代码“看到”相同的声明(通过使用相同的 stl 实现),或者从将模板添加到您的 API 中后退一步。

【讨论】:

  • +1:不仅同一个编译器,而且同一个编译器的同一个版本。例如,VS 2008 和 VS 2008 SP1 可能具有不同的 STL 类型实现。
  • 我的印象是像EXTERNAL_CORE template class PUBLIC_CORE std::deque&lt;int, std::allocator&lt;int&gt; &gt;; 这样的语句旨在通过__dllimport 强制编译消费者使用原始编译器的std::deque 实现。容器是我唯一真正遇到问题的东西(因为导出不那么复杂的东西似乎工作正常)。
  • @Travis:例如,目标编译器如何知道 std::deque 的原始实现是什么?
  • @John:我明白你的意思了......我开始看到当一个人声明extern template class __declspec(dllimport) std::deque&lt;int, std::allocator&lt;int&gt; &gt; 时实际发生了什么。似乎std::vector&lt;T&gt; 是唯一有效的导出,这很不方便。
  • @Travis:即使 std::vector 也不能真正“工作”。我将详细说明这一点...
猜你喜欢
  • 1970-01-01
  • 2014-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-29
  • 1970-01-01
相关资源
最近更新 更多