【问题标题】:Deriving custom archive classes from boost::archive::text_oarchive_impl and boost::archive::text_iarchive_impl从 boost::archive::text_oarchive_impl 和 boost::archive::text_iarchive_impl 派生自定义归档类
【发布时间】:2012-05-28 08:19:14
【问题描述】:

注意:
Boost 的归档方案基于对称的输入和输出归档类。一直写这两个都很乏味,所以我将使用?archive 来表示oarchiveiarchive

总结:
将我的自定义存档的基类从 binary_?archive_impl 更改为 text_?archive_impl 后,当编译器在我的其他类中实例化 serialize(...) 方法时,我的自定义存档类不再“找到”。

背景:
我的应用程序使用binary_?archive_impl 的子类成功地读取和写入文件到磁盘(文档和/或代码cmets 建议这样做而不是从binary_?archive 派生)。我需要从二进制文件格式切换到文本格式,因此我将自定义存档的基类切换为text_?archive_impl。就在那时,一切都爆发了。

问题:
我的自定义归档类添加了功能,包括一些在其 Boost 基类中不存在的附加方法;这些方法在我的许多课程中的serialize(...) 方法中被调用,并且它们运行良好。在将基类从binary_?archive_impl 更改为text_?archive_impl 后,我收到了到处都是编译错误,抱怨我的自定义方法在text_?archive不存在。嗯,这很明显(!!!),但它们确实存在在我的 custom 档案中,而且它们在我使用时正常 Boost 的二进制基类。有什么关系?

我发现了什么,以及我暂时的 - 但不受欢迎的 - 解决方案:
把头发扯下来绕圈转了大约一天,这就是我发现的……

1) 前段时间(我相信是 Boost 1.34),文件“binary_?archive.hpp”被拆分为“binary_?archive_impl.hpp”和“binary_?archive.hpp”(后者#include 前者)。这没有对“text_?archive.hpp”进行。 (因此,我将应用程序的 #include 行从“binary_?archive_impl.hpp”更改为简单的“text_?archive.hpp”。)

2) 如果我将“text_?archive.hpp”分成两部分并#include 仅“..._impl.hpp”标头,一切正常。 (但我真的不想想修改我的 Boost 安装!)

3) 更仔细地查看这些标题并摆弄了一下,我发现如果我使用原始的、未修改的标题并注释掉该行

BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::archive::text_oarchive)

(同样适用于text_iarchive),然后一切正常。 (顺便说一句,我自己的存档代码中有类似的行来“注册”我的自定义存档。)

谜团和我的困境:
A)为什么这些线条的存在会破坏作品? ...为什么删除它们会使事情起作用? ...我这样做可能会破坏(不知道)什么?

B) 为什么很久以前“text_?archive.hpp”文件没有与“binary_?archive.hpp”文件一起拆分? (图书馆坏了吗?应该修吗?)

C) 有没有办法在我的应用程序代码中解决这个问题修改我的 Boost 安装?

附言我正在使用 Boost 1.48 和 Visual Studio 2010(64 位)
P.P.S.我想以上所有内容都同样适用于text_w?archive

【问题讨论】:

    标签: c++ visual-c++ serialization boost boost-serialization


    【解决方案1】:

    尽我所能告诉它是 boost 序列化中的一个错误。我们会看到here.

    A)
    1. 与您一起添加 BOOST_SERIALIZATION_REGISTER_ARCHIVE 新存档不起作用,因为默认文本存档已经注册 - 似乎只允许注册。
    2. 删除它们使其工作,因为只有您的自定义类被注册。
    3. 通过删除它们,您破坏了使用默认文本存档的能力 - 您的课程将被注册。

    B)
    我相当确定“text_?archive.hpp”文件应该像“binary_?archive.hpp”文件一样被拆分。补丁提升了任何人?

    C)
    最好的解决方案是提交一个补丁来拆分文件。对于临时解决方案,最好的方法可能是将补丁文件放在本地项目中,直到补丁使其成为 boost。

    【讨论】:

      【解决方案2】:

      我希望这是一个评论,因为它是一个提示,而不是一个答案。但是,我没有看到为您的问题添加评论的选项(而且我认为编辑按钮不会做我想做的事情)。

      在我的 1.49.0 安装中,我还看到了 text 类型的相应实现文件。它们在 impl 目录中为 .ipp 格式。时间戳表明它们最近没有更改,因此应该与 1.48 相同。它可能会帮助您解决问题。

      据戴夫亚伯拉罕说,.ipp files are supposed to hide the implementation。不知道他们为什么选择不同的风格。

      ---------+ 1 stackoverflow 无 2936 2009 年 12 月 5 日 ./binary_iarchive_impl.hpp

      ---------+ 1 stackoverflow 无 2966 Dec 5 2009 ./binary_oarchive_impl.hpp

      ---------+ 1 stackoverflow 无 1392 Nov 25 2007 ./detail/basic_archive_impl.hpp

      ---------+ 1 stackoverflow 无 3458 2009 年 5 月 20 日 ./impl/text_iarchive_impl.ipp

      ---------+ 1 stackoverflow 无 3290 2005 年 7 月 2 日 ./impl/text_oarchive_impl.ipp

      ---------+ 1 stackoverflow 无 3020 2008 年 6 月 26 日 ./impl/text_wiarchive_impl.ipp

      ---------+ 1 stackoverflow 无 2244 2005 年 7 月 2 日 ./impl/text_woarchive_impl.ipp

      【讨论】:

      • 我确实注意到了这些文件(在我的 1.48 安装中),但它们不是解决方案。作为临时修复,我已经完成了将 text_?archive 标头拆分为单独文件的工作,并且该更改还需要对这些 .ipp 文件进行修改。所以我有一个临时解决方案,但我仍然不知道这是否应该报告为库中的错误,或者这些文件是否正确,我应该在我的代码中做一些不同的事情。
      【解决方案3】:

      我在为我的库实现自定义存档时遇到了同样的问题。 我找到了一个可能的解决技巧,它似乎效果很好,所以我会与你分享:

      没有办法在 boost 存档中导出具有修改的序列化语法的类,所以我们必须完全避免它。

      boost 存档注册使用适当重载的函数来制作指针序列化类型实例(如boost/archive/detail/register_archive.hpp

      # define BOOST_SERIALIZATION_REGISTER_ARCHIVE(Archive)                  \
      namespace boost { namespace archive { namespace detail {                \
                                                                              \
      template <class Serializable>                                           \
      BOOST_DEDUCED_TYPENAME _ptr_serialization_support<Archive, Serializable>::type  \
      instantiate_ptr_serialization( Serializable*, Archive*, adl_tag );              \
                                                                              \
      }}}
      

      请注意,adl_tag 添加了一个很酷的重载功能,可用于使 boost 能够查看我们的实现内部。只需将新的注册声明如下:

      // ARCHIVES REGISTRATION //
      
      namespace MyLib {
      struct adl_tag {};
      }
      
      namespace boost { namespace archive { namespace detail {
      template <class Serializable>
      void instantiate_ptr_serialization(Serializable*, int, MyLib::adl_tag ) {}
      } } }
      
      # define MYLIB_SERIALIZATION_REGISTER_ARCHIVE(_Archive)                   \
      namespace boost { namespace archive { namespace detail {                \
      template <class Serializable>                                           \
      BOOST_DEDUCED_TYPENAME _ptr_serialization_support<_Archive, Serializable>::type  \
      instantiate_ptr_serialization( Serializable*, _Archive*, MyLib::adl_tag ); }}}
      

      现在您必须像 (/boost/serialization/export.hpp) 一样制作自己的 EXPORT 宏:

      namespace MyLib {
      namespace extra_detail {
      
      template<class T>
      struct guid_initializer
      {
          void export_guid(mpl::false_) const {
              // generates the statically-initialized objects whose constructors
              // register the information allowing serialization of T objects
              // through pointers to their base classes.
              boost::archive::detail::
                      instantiate_ptr_serialization((T*)0, 0,
                                                    MyLib::adl_tag());
          }
          void export_guid(mpl::true_) const {
          }
          guid_initializer const & export_guid() const {
              BOOST_STATIC_WARNING(boost::is_polymorphic< T >::value);
              // note: exporting an abstract base class will have no effect
              // and cannot be used to instantitiate serialization code
              // (one might be using this in a DLL to instantiate code)
              //BOOST_STATIC_WARNING(! boost::serialization::is_abstract< T >::value);
              export_guid(boost::serialization::is_abstract< T >());
              return *this;
          }
      };
      
      template<typename T>
      struct init_guid;
      
      } // extra_detail
      } // namespace MyLib
      
      
      
      #define  MYLIB_CLASS_EXPORT_IMPLEMENT(T)                      \
          namespace MyLib  {                                        \
          namespace extra_detail {                                 \
          template<>                                               \
          struct init_guid< T > {                                  \
              static guid_initializer< T > const & g;              \
          };                                                       \
          guid_initializer< T > const & init_guid< T >::g =        \
              ::boost::serialization::singleton<                   \
                  guid_initializer< T >                            \
              >::get_mutable_instance().export_guid();             \
          }}                                                     \
      /**/
      

      好了,现在您可以定义您的自定义存档并将其注册到:

      MYLIB_SERIALIZATION_REGISTER_ARCHIVE(MyLib::xml_iarchive)
      

      任何时候你为你的类定义一个序列化,它的特定语法只能由 MyLib::custom_archive 读取,你可以使用你的导出实现

      BOOST_CLASS_EXPORT_KEY(MyClass) // in header
      MYLIB_CLASS_EXPORT_IMPLEMENT(MyClass) // in cpp
      

      (请注意,Key 的导出与 boost ... 相同)

      这真的很酷,因为可以让您的自定义存档和 boost 存档一起存在而不会出现错误。任何时候您想要一个 boost 序列化只需使用 BOOST_CLASS_EXPORT,而任何时候您要序列化您的类使用 MYLIB_CLASS_EXPORT。

      希望这可能有用!

      安德烈亚·里戈尼·加罗拉

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-05-03
        • 1970-01-01
        • 1970-01-01
        • 2011-08-05
        • 2011-04-24
        • 2015-06-13
        • 2012-03-22
        相关资源
        最近更新 更多