C++ Boost

Serialization

Derivation from an Existing Archive


Log Archive

It may happen that one wants to create a new archive class by derivation from one of the included ones. Included is a sample program that shows how to derive a new archive from one of the ones included with the library. The first example is demo_log.cpp.

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

  1. It is derived from xml_oarchive_impl NOT xml_oarchive
    As described in the comments in xml_oarchive.hpp. 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>
    {
    ...
    
  2. Note the 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.
  3. Base classes need to be explicitly given access to the derived class. This can be done by making members public or by including friend declarations for the base classes.
    
        friend class detail::common_oarchive<log_archive>;
        friend class basic_xml_oarchive<log_archive>;
        friend class boost::serialization::save_access;
    
  4. Reread Archive Internals. This describes the class hierarchy so that you know what to override.
  5. Note the usage of PFTO. Some compilers fail to provide support for partial function template ordering. The serialization library works around this by using Partial Function Template Ordering in several places. This is done in several places, including the archive classes themselves.
  6. Base class functions will usually need to be explicitly invoked. We commonly specialize the function name 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.
  7. Template definitions of base classes may have to be explicitly instantiated. The demo includes
    
    // 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.
  8. Without alteration, this class cannot be further derived from.
    Base classes using CRTP must be templates with a parameter corresponding to the most derived class. As presented here, this class doesn't qualify, so it cannot be used as a base class. In order to derive further from this class, it would have to be reorganized along the lines of the original 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<xml_oarchive>(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)