从boost :: archive :: text_oarchive_impl和boost :: archive :: text_iarchive_impl派生自定义归档类

时间:2012-05-21 20:10:35

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

注意:
Boost的归档方案基于对称的输入和输出归档类。一直写两篇文章都很繁琐,所以我会?archive来表示oarchiveiarchive

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

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

问题:
我的自定义归档类添加了功能,包括其Boost基类中不存在的一些其他方法;这些方法在我的许多类中的serialize(...)方法中调用,它们正常工作。将基类从binary_?archive_impl更改为text_?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安装?

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

3 个答案:

答案 0 :(得分:1)

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

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

根据Dave Abrahams,.ipp files are supposed to hide the implementation。不知道为什么他们选择不同的风格。

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

---------- + 1 stackoverflow无2966 2009年12月5日./binary_oarchive_impl.hpp

---------- + 1 stackoverflow无1392 2007年11月25日./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 Jun 26 2008 ./impl/text_wiarchive_impl.ipp

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

答案 1 :(得分:1)

我最好能告诉它序列化中的一个错误。我们会看到here.

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

<强>乙
我很确定“text_?archive.hpp”文件应该像“binary_?archive.hpp”文件一样被拆分。补丁提升任何人?

<强> C
最好的解决方案是提交一个补丁来提升分割文件。对于临时解决方案,最好的方法是将修补后的文件放在项目本地,直到补丁进入提升状态。

答案 2 :(得分: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 ); }}}

现在你必须像(/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_CLASS_EXPORT,并且只要你的类被序列化,就可以使用MYLIB_CLASS_EXPORT。

希望这可能有用!

Andrea Rigoni Garola