来自靴子/序列化的documentation:
... BOOST_CLASS_EXPORT_GUID显式实例化程序使用的所有归档类的类序列化代码。
我查看了源代码,发现了这个:
#define BOOST_CLASS_EXPORT_IMPLEMENT(T) \
namespace boost { \
namespace archive { \
namespace detail { \
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(); \
}}}} \
/**/
#define BOOST_CLASS_EXPORT_KEY2(T, K) \
namespace boost { \
namespace serialization { \
template<> \
struct guid_defined< T > : boost::mpl::true_ {}; \
template<> \
inline const char * guid< T >(){ \
return K; \
} \
} /* serialization */ \
} /* boost */ \
/**/
#define BOOST_CLASS_EXPORT_GUID(T, K) \
BOOST_CLASS_EXPORT_KEY2(T, K) \
BOOST_CLASS_EXPORT_IMPLEMENT(T) \
/**/
我理解,BOOST_CLASS_EXPORT_KEY2
如何工作 - 它定义了模板,表明给定的类定义了GUID并存储了这个字符串。
但BOOST_CLASS_EXPORT_IMPLEMENT如何运作?我一遍又一遍地阅读它,但我看不出它是如何显式实例化所有存档类的类序列化代码 ......
我写了下面的例子,它按预期工作,但是当我调试它时,结构太复杂了,我还是不明白。
示例:
#include <vector>
#include <sstream>
#include <iostream>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/smart_ptr.hpp>
#define UNUSED(i_param) ((void)i_param)
class Base
{
public:
Base(int i_baseValue) :
m_baseValue(i_baseValue)
{
}
virtual ~Base()
{
}
virtual void print() = 0;
protected:
int m_baseValue;
private:
friend class ::boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int file_version)
{
UNUSED(file_version);
ar & m_baseValue;
}
};
class A : public Base
{
public:
A(int i_aValue, int i_baseValue) :
Base(i_baseValue),
m_aValue(i_aValue)
{
}
A() :
Base(-1),
m_aValue(-1)
{
}
~A()
{
}
void print()
{
::std::cout << "A, base: " << m_baseValue << ", a: " << m_aValue << ::std::endl;
}
private:
friend class ::boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int file_version)
{
UNUSED(file_version);
ar & ::boost::serialization::base_object<Base>(*this);
ar & m_aValue;
}
int m_aValue;
};
class B : public Base
{
public:
B(int i_bValue, int i_baseValue) :
Base(i_baseValue),
m_bValue(i_bValue)
{
}
B() :
Base(-2),
m_bValue(-2)
{
}
~B()
{
}
void print()
{
::std::cout << "B, base: " << m_baseValue << ", b: " << m_bValue << ::std::endl;
}
private:
friend class ::boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int file_version)
{
UNUSED(file_version);
ar & ::boost::serialization::base_object<Base>(*this);
ar & m_bValue;
}
int m_bValue;
};
typedef ::boost::shared_ptr<Base> BasePtr;
BOOST_CLASS_EXPORT_GUID(Base, "base")
BOOST_CLASS_EXPORT_GUID(A, "A")
BOOST_CLASS_EXPORT_GUID(B, "B")
void printAll(::std::vector<BasePtr>& data)
{
std::cout << " --- " << ::std::endl;
for(size_t i = 0; i < data.size(); ++i)
{
data[i]->print();
}
std::cout << " --- " << ::std::endl;
}
int main()
{
::std::stringstream stream;
{
::std::vector<BasePtr> data;
data.push_back(BasePtr(new A(10, 20)));
data.push_back(BasePtr(new B(33, 44)));
printAll(data);
::boost::archive::text_oarchive ar(stream);
ar & data;
}
//::std::cout << "Data:\n" << stream.str() << "\n";
{
::std::vector<BasePtr> data;
stream.seekg(0);
::boost::archive::text_iarchive ar(stream);
ar & data;
printAll(data);
}
return 0;
}
输出:
---
A, base: 20, a: 10
B, base: 44, b: 33
---
---
A, base: 20, a: 10
B, base: 44, b: 33
---
按预期工作。
注意:有些人可能会问为什么我想知道这一点。我不认为这很重要,但这是因为我需要一些序列化代码,但由于某些原因,提升对我来说无法使用。所以我正在研究是否可以修改我的需求(例如通过实现自定义存档+一些核心代码修改)或者是否更好地实现自己的东西。对于这两种情况,我想知道,它是如何工作的,所以我可以确定它是否可用于我的情况或我是否可以模仿这种行为。第三个原因只是好奇心和对知识的渴望。
更新
经过多个小时的挖掘,我发现它就在这里(来自提升):
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.
instantiate_ptr_serialization((T*)0, 0, 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;
}
};
注册档案时在此处理:
// This function gets called, but its only purpose is to participate
// in overload resolution with the functions declared by
// BOOST_SERIALIZATION_REGISTER_ARCHIVE, below.
template <class Serializable>
void instantiate_ptr_serialization(Serializable*, int, adl_tag ) {}
// The function declaration generated by this macro never actually
// gets called, but its return type gets instantiated, and that's
// enough to cause registration of serialization functions between
// Archive and any exported Serializable type. See also:
// boost/serialization/export.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 ); \
\
然而,我仍然看不出它是如何运作的。从文档中我只了解其用法,而不是原理如何工作。您需要注册Archive
实现,然后导出派生类将为每个注册的存档的每一端创建序列化方法专门化。怎么样?