【问题标题】:Error C2562 when using (and exporting) boost::shared_ptr<T>使用(和导出) boost::shared_ptr<T> 时出现错误 C2562
【发布时间】:2013-12-28 16:50:48
【问题描述】:

各位程序员们好,

我正在创建一个 C++ DLL 库,我在其中使用了 boost 的 (1.55) shared_ptr。 但是,当我使用 Visual Studio 2013 编译项目时,会出现一堆疯狂的错误 C2562:

Error   1   error C2562: 'boost::shared_ptr<MEngine::i18n::ITranslationSource>::operator []' : 'void' function returning a value    f:\developer\cplus\lib\boost_1_55_0\boost\smart_ptr\shared_ptr.hpp  663 1   MEngine
Error   2   error C2562: 'boost::shared_ptr<MEngine::i18n::ITranslationSource>::operator []' : 'void' function returning a value    f:\developer\cplus\lib\boost_1_55_0\boost\smart_ptr\shared_ptr.hpp  663 1   MEngine
Error   3   error C2562: 'boost::shared_ptr<MEngine::Object::GameObject>::operator []' : 'void' function returning a value  f:\developer\cplus\lib\boost_1_55_0\boost\smart_ptr\shared_ptr.hpp  663 1   MEngine
Error   4   error C2562: 'boost::shared_ptr<MEngine::Object::GameObject>::operator []' : 'void' function returning a value  f:\developer\cplus\lib\boost_1_55_0\boost\smart_ptr\shared_ptr.hpp  663 1   MEngine
Error   5   error C2562: 'boost::shared_ptr<MEngine::Object::GameObject>::operator []' : 'void' function returning a value  f:\developer\cplus\lib\boost_1_55_0\boost\smart_ptr\shared_ptr.hpp  663 1   MEngine
Error   6   error C2562: 'boost::shared_ptr<MEngine::i18n::ITranslationSource>::operator []' : 'void' function returning a value    f:\developer\cplus\lib\boost_1_55_0\boost\smart_ptr\shared_ptr.hpp  663 1   MEngine
Error   7   error C2562: 'boost::shared_ptr<MEngine::i18n::ITranslationSource>::operator []' : 'void' function returning a value    f:\developer\cplus\lib\boost_1_55_0\boost\smart_ptr\shared_ptr.hpp  663 1   MEngine
Error   8   error C2562: 'boost::shared_ptr<MEngine::i18n::ITranslationSource>::operator []' : 'void' function returning a value    f:\developer\cplus\lib\boost_1_55_0\boost\smart_ptr\shared_ptr.hpp  663 1   MEngine

如您所见,每个 shared_ptr 模板实例化都有相同的错误。 问题是我从不使用那个运算符,所以不应该不生成它的代码吗?

在这种情况下,为什么会出现该错误是完全可以理解的,因为在 shared_ptr.h 中有这样的:

typename boost::detail::sp_array_access< T >::type operator[] ( std::ptrdiff_t i ) const
{
    BOOST_ASSERT( px != 0 );
    BOOST_ASSERT( i >= 0 && ( i < boost::detail::sp_extent< T >::value || boost::detail::sp_extent< T >::value == 0 ) );

    return px[ i ];
}

还有:

template< class T > struct sp_array_access
{
    typedef void type;
};
...
template< class T > struct sp_array_access< T[] >
{
    typedef T & type;
};
...

这意味着对于 smart_ptr,如果 T 不是数组,则 operator[] 的返回类型为 void,因此运算符的代码将无法编译。

所以真正的问题是(我认为)操作符的代码是生成的,但它不应该生成。 我需要将 shared_ptr 导出到我的 DLL 接口,因为它是一个模板,所以我使用它来实例化和导出它:

EXPIMP_TEMPLATE template class MENGINE_API boost::shared_ptr<MEngine::i18n::ITranslationSource>;

宏在哪里(非常标准):

#ifdef MENGINE_EXPORTS
#define MENGINE_API _declspec(dllexport)
#define EXPIMP_TEMPLATE
#else
#define MENGINE_API _declspec(dllimport)
#define EXPIMP_TEMPLATE extern
#endif

我使用的导出语句是否会导致模板中所有内容的生成? 如果这是真的,那么我该如何克服这一点并实现出口?

为我的英语道歉 :) 也非常感谢纠正我,因为我愿意学习:)

【问题讨论】:

  • 模板类不应该是公共 Dll 接口的一部分。
  • 我承认后果,并且该库旨在用于完全控制工具链以及包含的标头和链接库的版本的环境。我实际上是在发布源代码。

标签: c++ windows visual-studio boost dll


【解决方案1】:

C++11 14.7.2 [temp.explicit] 第 8 段:

命名类模板特化的显式实例化也是 每个成员(不包括从基类继承的成员)的相同类型(声明或定义) classes) 之前没有在包含显式的翻译单元中显式特化 实例化,但下面描述的除外。

在不支持“下面描述”的所有细节的情况下,您的显式实例化会实例化所有定义明确或其他方式的成员。这是显式实例化的要点:将每个成员的所有代码都定义在一个地方。在实例化时,尚不清楚是否会实际使用哪些成员:据您所知,链接到您的库的某些客户端可能会使用 operator[]

理想的解决方法是(此处胡乱猜测)使用std::enable_if 删除非数组类型的operator[] 重载,而不是使非数组类型的代码格式错误。

其他一些选项:

  • 不要显式实例化任何东西。
  • 单独显式实例化每个所需成员,避免使用格式错误的成员。

【讨论】:

  • 根据 boost 的 shared_ptr 的设计,如果 T 不是数组类型,则用户不能使用 operator[](它会导致生成运算符代码并导致 C2562,如我的情况)并且它不是任何我的明确实例化。我对 enable_if 不是很熟悉,但不使用它意味着我需要修改 boost 的代码(不太可能)?
  • @MichaelK.Sondej 问题在于设计并没有使不正确的运算符无法使用,而是使它们格式错误。模板特化的显式实例化强制实例化所有成员——即使是格式错误的成员——将其作为一个可用的解决方案从桌面上移除。您的其他几个选择是显式地逐个成员实例化,而不是一次性显式实例化整个类,或者干脆完全避免显式实例化。
  • 但是如何避免呢?是否可以在没有显式实例化的情况下将模板化对象导出到 dll 接口?非模板类中的封装实际上没有任何意义,另一方面,我认为我自己的模板类中的封装根本行不通(实现在标题中,因此也需要导出 boost::shared_ptr ?)。
  • @MichaelK.Sondej Here's an example of what I mean by instantiating individual members instead of entire template classes。也就是说,如果您将boost::shared_ptr“泄漏”到您的DLL 的客户端,您已经严重依赖使用shared_ptr 的相同标头实现的客户端。我认为通过从 DLL 导出 shared_ptr&lt;YourClass&gt; 而不是简单地导出 YourClass 并让客户端从标题中实例化 shared_ptr&lt;YourClass&gt; 自己不会获得任何好处。
  • 我不知道它会起作用,看来我必须阅读更多关于 DLL 的信息。谢谢!
猜你喜欢
  • 2018-07-13
  • 1970-01-01
  • 2017-07-20
  • 1970-01-01
  • 2017-07-23
  • 1970-01-01
  • 2018-02-19
  • 2017-08-11
  • 1970-01-01
相关资源
最近更新 更多