I am newbie and I want to implement an interface to force users to implement the serialize method. This method is template and I can not define as virtual.
I would like the user only has to implement a function like this:
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
...
};
I try to create this interface:
class interface_serializing
{
public:
virtual ~interface_serializing(void)
{ }
friend class boost::serialization::access;
virtual void serialize(boost::archive::polymorphic_iarchive & ar,
const unsigned int version) = 0;
virtual void serialize(boost::archive::polymorphic_oarchive & ar,
const unsigned int version) = 0;
};
But it forces the user to implement these two methods and is not what I want.
Is there any way to do what I want?
Thank you
There's no builtin way, but you can, of course, always abstract any interface you wish, with the right set of trade-offs.
Here's one imagined solution that uses a custom PolyArchive
that could be a reference to either the polymorphic_oarchive
or polymorphic_iarchive
:
#include <boost/serialization/serialization.hpp>
#include <boost/archive/polymorphic_oarchive.hpp>
#include <boost/archive/polymorphic_iarchive.hpp>
#include <boost/archive/polymorphic_text_oarchive.hpp>
#include <boost/archive/polymorphic_text_iarchive.hpp>
#include <boost/variant.hpp>
#include <sstream>
using PolyArchive = boost::variant<
boost::archive::polymorphic_oarchive&,
boost::archive::polymorphic_iarchive&
>;
struct /*abstract*/ ISerializable {
virtual void serialize(PolyArchive, unsigned) = 0;
};
struct MyClass : ISerializable {
std::string data_member = "Morgana"; // something to serialize
// the one method we need to implement
virtual void serialize(PolyArchive ar, unsigned) override;
};
Now, let's do the implementation a bit with a bit of C++14 fairy-dust:
void MyClass::serialize(PolyArchive ar, unsigned) {
boost::apply_visitor(make_visitor([=](auto& ar) {
ar & data_member;
}), ar);
}
The astute reader will spot that the user still supplies the template method, but hides it inside a virtual method that actually takes a PolyArchive
at compile time.
Full Demo
See it Live On Coliru, printing:
Serialized: 22 serialization::archive 11 0 0 7 Morgana
Roundtripped: 22 serialization::archive 11 0 0 7 Morgana
Code:
#include <boost/serialization/serialization.hpp>
#include <boost/archive/polymorphic_oarchive.hpp>
#include <boost/archive/polymorphic_iarchive.hpp>
#include <boost/archive/polymorphic_text_oarchive.hpp>
#include <boost/archive/polymorphic_text_iarchive.hpp>
#include <boost/variant.hpp>
#include <sstream>
using PolyArchive = boost::variant<
boost::archive::polymorphic_oarchive&,
boost::archive::polymorphic_iarchive&
>;
struct /*abstract*/ ISerializable {
virtual void serialize(PolyArchive, unsigned) = 0;
};
struct MyClass : ISerializable {
std::string data_member = "Morgana"; // something to serialize
// the one method we need to implement
virtual void serialize(PolyArchive ar, unsigned) override;
};
int main()
{
std::stringstream ss;
{
// serialize:
boost::archive::polymorphic_text_oarchive output(ss);
MyClass object;
output << object;
}
// Debug dump;
std::cout << "Serialized: " << ss.str();
{
// read back:
boost::archive::polymorphic_text_iarchive input(ss);
MyClass cloned;
input >> cloned;
std::cout << "Roundtripped: ";
boost::archive::polymorphic_text_oarchive pta(std::cout);
pta << cloned;
}
}
////////////////////////////////
// implementation:
namespace /*detail*/ {
template <typename F> struct wrap_visitor : boost::static_visitor<> {
wrap_visitor(F const& f) : f_(f) { }
wrap_visitor(F&& f) : f_(std::move(f)) { }
template<typename... T> void operator()(T&&... t) const {
f_(std::forward<T>(t)...);
}
private:
F f_;
};
template <typename F>
wrap_visitor<F> make_visitor(F&& f) {
return std::forward<F>(f);
}
}
void MyClass::serialize(PolyArchive ar, unsigned) {
boost::apply_visitor(make_visitor([=](auto& ar) {
ar & data_member;
}), ar);
}