I need to serialize all the options on my CommunicationLayer, which is basically a wrapper around serial port, which I will use in an initialization file of sorts.
This class doesn't have a default constructor, but implements a pure virtual class. When I first ran this I got the exception that I didn't register/export the derived class. So I did that. But when I added the export I got the exception that it couldn't find a save/load function:
no matching function for call to ‘save(boost_1_69_0::archive::xml_oarchive&, const amp::communication::RS485CommunicationLayer&, const boost_1_69_0::serialization::version_type&)’
save(ar, t, v);
This is true! But I can't use the save/load and use save_construct_data and load_construct_data, because the absence of a default constructor. How do I tell boost/serde to use these instead?? Is it the SPLIT_FREE macro?
I'm trying to work myself through the documentation, but it's really hard to find everything.
Following are the base and derived classes, I tried to shorten the derived class as much as possible.
//BASE
class ICommunicationLayer {
friend class boost::serialization::access;
template<class Archive>
inline void serialize(Archive & ar, const unsigned int file_version) {};
public:
virtual ~ICommunicationLayer();
virtual std::size_t write(const char* const buffer, std::size_t buffSize) = 0;
virtual std::size_t readUntil(std::vector<char>& buffer, char delim, std::chrono::microseconds timeout) = 0;
};
// DERIVED
#include "ICommunicationLayer.h"
#include <boost/asio.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/split_free.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/nvp.hpp>
namespace amp {
namespace communication {
class RS485CommunicationLayer final : public ICommunicationLayer {
public:
RS485CommunicationLayer(
const std::string& path,
unsigned int baud_rate,
// other options
);
~RS485CommunicationLayer();
std::size_t write(const char* const buffer, const size_t size) override;
std::size_t readUntil(std::vector<char>& buffer, char delim,std::chrono::microseconds timeout) override;
std::string getPath() const;
private:
friend class boost::serialization::access;
std::string path;
// rest of impl
};
} /* namespace communication */
} /* namespace amp */
BOOST_SERIALIZATION_SPLIT_FREE(amp::communication::RS485CommunicationLayer)
BOOST_CLASS_EXPORT(amp::communication::RS485CommunicationLayer)
namespace boost_1_69_0 {
namespace serialization {
template<class Archive>
inline void save_construct_data(Archive& ar, const amp::communication::RS485CommunicationLayer* comLayer, const unsigned int version) {
ar << boost::serialization::make_nvp(
BOOST_PP_STRINGIZE(amp::communication::ICommunicationLayer),
boost::serialization::base_object<amp::communication::ICommunicationLayer>(*comLayer)
);
ar << boost::serialization::make_nvp("path", const_cast<std::string>(comLayer->getPath());
// other options
}
template<class Archive>
inline void load_construct_data(Archive& ar, amp::communication::RS485CommunicationLayer* comLayer, const unsigned int version) {
ar >> boost::serialization::base_object<amp::communication::ICommunicationLayer>(*comLayer);
std::string path;
ar >> path;
// other options
new(comLayer) amp::communication::RS485CommunicationLayer(path, baudrate, /* other options */);
}
}
}
The construct data is an addition to regular serialization. You still need to serialize. As a matter of fact, serializing
base_objectneeds to be in the constructed-objectserializeimplementation.Also keep in mind that you need to EXPORT after including the relevant archive type(s).
You have a number of spots with redundant top-level const (even a const-cast). Top-level const on return type/arguments isn't part of the function signature.
Finally, I don't know what
namespace boost_1_69_0is, but that should not work. Usenamespace boost. If you're playing with macros to define it like that, I'd suggest to stop doing that. Instead consider putting the overloads in the ADL-associated namespace for your types!Here's the whole thing made self-contained and working:
Live On Coliru
Prints
Afterthought
Perhaps the best location for load/save construct data is as hidden friends. That way you don't even need public accessors for every bit of construct-data:
Live On Coliru