There's two issues at play here:
You are serializing a template class. This is not a problem and yes you can do this intrusively (member
serialize
) or non-intrusively (free functionserialize
via ADL). As the documentation (Serializing Templates) states the implementation ofshared_ptr<T>
serialization is a good example of the non-intrusive variant here:You are serializing base/derived classes through a polymorphic pointer. For the serialization part this is nothing special (you can
register_type
or you should be fine usingbase_object<Interface>(this)
inside the derived'sserialize
function.On the deserialization side of things, however, you need to anticipate the full list of possible concrete instance types serialized through the polymorphic pointer. The
BOOST_EXPORT_CLASS
macro is the easiest way to achieve this. You will have to list the concrete instances of the template you wish to support, though:BOOST_CLASS_EXPORT(Derived<std::string>) BOOST_CLASS_EXPORT(Derived<double>) BOOST_CLASS_EXPORT(Derived<int>) // include all subtypes we can expect in an input archive
or
BOOST_CLASS_EXPORT_GUID(Derived<std::string>, "4ef5a3ff-168a-4242-846b-4886f48424b5") BOOST_CLASS_EXPORT_GUID(Derived<double>, "d0ed9de6-584f-476d-9898-8234bcb4efdb") BOOST_CLASS_EXPORT_GUID(Derived<int>, "505538f0-2dd1-43bd-92a2-506ed9659bbe") // include all subtypes we can expect in an input archive
The complexity of the situation - and the confusion - arises from the fact that you are serializing a derived class template through a polymorphic pointer. All at the same time. But conceptually both are easily tackled.
Slightly unrelated,
- Yes, you can use free function serialize, see the 3rd alternative version below. It gains you little though, and just requires
m_data
to be publicly accessible.- Do not use
serialize_adl
as it is an implementation detail
Here are three samples that integrates everything:
Live On Coliru - raw
Interface*
Live On Coliru - same with
shared_ptr<Interface>
Live On Coliru - same with non-intrusive
serialize
function
Listing for the first sample
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <sstream>
class Interface {
public:
virtual void aVirtual() = 0;
virtual ~Interface() {}
private:
friend class boost::serialization::access;
template<class Archive> void serialize(Archive&, unsigned) { }
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Interface)
template<class T>
class Derived : public Interface {
public:
Derived(T in = 0) : m_data(in) {}
virtual void aVirtual() { /*Do something*/ }
T const& getData() const { return m_data; }
private:
T m_data;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, unsigned)
{
ar & boost::serialization::base_object<Interface>(*this);
//// alternatively, if you don't want to make the abstract base serializable:
// boost::serialization::void_cast_register<Derived, Interface>();
ar & m_data;
}
};
BOOST_CLASS_EXPORT(Derived<std::string>)
BOOST_CLASS_EXPORT(Derived<double>)
BOOST_CLASS_EXPORT(Derived<int>) // include all subtypes we can expect in an input archive
int main()
{
std::stringstream ss;
{
boost::archive::text_oarchive oa(ss);
Interface* o = new Derived<int>(42);
oa << o;
delete o;
}
std::cout << "Serialized: '" << ss.str() << "'\n";
{
boost::archive::text_iarchive ia(ss);
Interface* o = nullptr;
ia >> o;
if (auto p = dynamic_cast<Derived<int>*>(o))
std::cout << "Deserialized into Derived<int> with data: " << p->getData() << "\n";
delete o;
}
}
Sample output:
Serialized: '22 serialization::archive 11 0 1 1 12 Derived<int> 1 0
0 42
'
Deserialized into Derived<int> with data: 42