注意:
Boost的归档方案基于对称的输入和输出归档类。一直写两篇文章都很繁琐,所以我会?archive
来表示oarchive
和iarchive
。
要点:
将自定义归档的基类从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
答案 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