10

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

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

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

问题:
我的自定义归档类添加了功能,包括一些在其 Boost 基类中不存在的附加方法;这些方法serialize(...)在我的许多课程的方法中被调用,并且它们工作正常。将基类从 更改为 后binary_?archive_impltext_?archive_impl我到处都收到编译错误,抱怨我的自定义方法text_?archive. 嗯,这很明显(!!!),但它们确实存在于我的自定义档案中,当我使用 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 安装?

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

4

3 回答 3

1

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

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

根据 Dave Abrahams 的说法,.ipp 文件应该隐藏实现。不知道他们为什么选择不同的风格。

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

----------+ 1 stackoverflow 无 2966 2009 年 12 月 5 日 ./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

于 2012-05-28T19:29:26.133 回答
1

尽我所能告诉它提升序列化中的一个错误。我们会在这里看到。

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

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

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

于 2012-06-29T05:33:10.097 回答
0

我在为我的图书馆实施自定义存档时遇到了同样的问题。我找到了一个可能的解决方案,它似乎效果很好,所以我将与您分享:

无法在 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 ); }}}

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

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。

希望这可能有用!

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

于 2013-08-24T13:11:09.843 回答