Serialization of derived class from templated class versioning

Viewed 114

I'm trying to serialize a class derived from a template class, where I fix the template argument. I want to serialize the base class independently from the derived one in case I fix the template to some other type and I want the derived class to serialize to base class plus some other data. When I do this in my minimal example:

#include <iostream>
#include <sstream>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/traits.hpp>
#include <boost/serialization/level.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

using namespace boost::archive;
static constexpr unsigned int base_version = 1;

template<typename T>
struct Base : public boost::serialization::traits<Base<T>,
                                                 boost::serialization::object_class_info,
                                                 boost::serialization::track_never,
                                                 base_version> {
  T t;
  template<typename A>
  void load(A& a,
            unsigned int const in_version) {
    std::cerr << "Loading Base with version " << in_version  << std::endl;
    a & t;
  }
  template<typename A>
  void save(A& a,
            unsigned int const) const {
    std::cerr << "Saving Base with version " << base_version << std::endl;
    a & t;
  }
  BOOST_SERIALIZATION_SPLIT_MEMBER()
};

struct Derived : public Base<int> {
  int j;
  static constexpr unsigned int version = 2;
  template<typename A>
  void load(A& a,
            unsigned int const in_version) {
    std::cerr << "Loading Derived with version " << in_version << std::endl;
    a & boost::serialization::base_object<Base>(*this);
    a & j;
  }
  template<typename A>
  void save(A& a,
            unsigned int const) const {
    std::cerr << "Saving Derived with version " << version << std::endl;
    a & boost::serialization::base_object<Base>(*this);
    a & j;
  }
  BOOST_SERIALIZATION_SPLIT_MEMBER()
};
BOOST_CLASS_VERSION(Derived,Derived::version)

int main() {
  Derived d;
  d.t = 1;

  std::stringstream s;
  text_oarchive oa {s};
  oa << d;

  Derived e;
  text_iarchive ia{s};
  ia >> e;
  std::cerr << e.t << std::endl;

  return 0;
}

I get as an output:

Saving Derived with version 2
Saving Base with version 1
Loading Derived with version 2
Loading Base with version 2
1

It seems that the saving is done with the correct versions, while the load is always done with the version of the derived class. What is wrong with this code?

1 Answers

Defining the version of Base not via inheritance but by specialising a member of the boost::serialization namespace leads to the desired behaviour for me:

// headers as before
#define BOOST_CLASS_TEMPLATE_VERSION(Template, Type, Version) \
namespace boost {                                           \
  namespace serialization {                                 \
    template<Template>                                      \
    struct version<Type> {                                  \
      static constexpr unsigned int value = Version;        \
    };                                                      \
    template<Template>                                      \
    constexpr unsigned int version<Type>::value;            \
  }                                                         \
}

using namespace boost::archive;
static constexpr unsigned int base_version = 1;

template<typename T>
struct Base {
  T t;
// ...
};
BOOST_CLASS_TEMPLATE_VERSION(typename T, Base<T>, base_version);
// rest as before

gives

$ ./main 
Saving Derived with version 2
Saving Base with version 1
Loading Derived with version 2
Loading Base with version 1
1

with Boost 1.67.

Related