|
|
SerializationDerivation from an Existing Archive |
This derivation from the xml archive writes output in xml without the extra information required to read the data back into the application. It might be used to export one's data as simple xml for other applications or for logging data while debugging.
To this end it is derived from the included xml archive and the save functions for some types are specialized for this application.
The serialization library is implemented using the Curiously Recurring Template Pattern (CRTP). Also, all common code is factored out into separate modules to minimize code repetition. This makes derivation from an existing archive less straightforward than it would otherwise be.
This example illustrates several issues that have to be addressed when doing something like this
xml_oarchive_impl
NOT xml_oarchive xml_oarchive really a shorthand name for
xml_oarchive_impl<xml_oarchive>. So we should derive
from xml_oarchive_impl<log_archive> rather
than xml_oarchive.
class log_archive :
// don't derive from xml_oarchive !!!
public xml_oarchive_impl<log_archive>
{
...
log_archive between the <>
This is required so that base classes can downcast their this pointer
to the most derived class. This is referred to as Curiously Recurring
Template Pattern (CRTP) [11].
It is used to implement static polymorphism.
init().
The archive header (signature and version) is written by init().
Before Boost 1.73, the CRTP base called init() from its own
constructor, but that downcast this to the most derived class
while that class was still being constructed, which is undefined behavior. As of 1.73, the base
classes no longer do this, so a derived archive that wants the standard header must call
init() itself, in its own constructor body, after the base
sub-objects have been constructed, honoring the no_header flag:
log_archive(std::ostream & os, unsigned int flags = 0) :
xml_oarchive_impl<log_archive>(os, flags)
{
if(0 == (flags & boost::archive::no_header))
init();
}
The log_archive shown in this example passes
no_header, so it has no header to write and its constructor
body is empty; see xml_oarchive, or the
portable_binary_oarchive example, for archives that do write one.
friend class detail::common_oarchive<log_archive>;
friend class basic_xml_oarchive<log_archive>;
friend class boost::serialization::save_access;
save_override
for saving primitives. Usage of a function name in a derived class
"hides" similarly named functions of the base class. That is,
function name overloading doesn't automatically
include base classes. To address this, we can use:
using xml_oarchive_impl<derived_t>::save;
void save(const unsigned int t);
...
which should work on conforming compilers. However, I have found
that the following equivalent works on more compilers.
// default fall through for any types not specified here
template<class T>
void save(const T & t){
xml_oarchive_impl<derived_t>::save(t);
}
void save(const unsigned int t);
...
so it's what I use.
// explicitly instantiate for this type of binary stream
#include <boost/archive/basic_binary_oprimitive.ipp>
for just this purpose. Failure to include required template definitions
will result in undefined symbol errors when the program is linked.
xml_oarchive.
Specifically, it would look something like:
template<class Archive>
class log_archive_impl :
// don't derive from xml_oarchive !!!
public xml_oarchive_impl<Archive>
{
...
};
// do not derive from this class !!!
class log_archive :
public log_archive_impl<log_archive>
{
public:
log_archive(std::ostream & os, unsigned int flags = 0) :
log_archive_impl<log_archive>(os, flags)
{}
};
© Copyright Robert Ramey 2002-2004. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)