Simple extension of boost::archive::text_oarchive - c++

I am trying to add a member variable to a Boost archive class. Following this, I came up with:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <fstream>
class MyOArchive : public boost::archive::text_oarchive_impl<MyOArchive>
{
public:
bool MyData;
friend class boost::archive::detail::common_oarchive<MyOArchive>;
friend class basic_text_oarchive<MyOArchive>;
//friend class boost::serialization::save_access; // save_access in namespace boost::serialization does not name a type
MyOArchive(std::ostream& os, unsigned int flags = 0) : boost::archive::text_oarchive_impl<MyOArchive>(os, flags) {}
};
class MyClass
{
public:
private:
friend class boost::serialization::access;
double Value;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & Value;
}
};
int main()
{
MyClass myClass;
std::ofstream outputStream("test.txt");
//boost::archive::text_oarchive outputArchive(outputStream);
MyOArchive outputArchive(outputStream);
outputArchive << myClass;
outputStream.close();
return 0;
}
However, I am getting linker errors:
undefined reference to boost::archive::text_oarchive_impl<MyOArchive>::text_oarchive_impl(std::ostream&, unsigned int)
Can anyone explain what is going wrong here? I don't need to reimplement any of the functions of the archive, just attach this member MyData.

Ah. Spotted it.
You need to include the ipps for the basic implementations in exactly one TU that's linked into the end product.
#include <boost/archive/impl/basic_text_oarchive.ipp>
#include <boost/archive/impl/text_oarchive_impl.ipp>
Also, save_access lives in a different castle namespace:
friend class boost::archive::save_access;
Live On Coliru
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/impl/basic_text_oarchive.ipp>
#include <boost/archive/impl/text_oarchive_impl.ipp>
#include <fstream>
class MyOArchive : public boost::archive::text_oarchive_impl<MyOArchive> {
public:
bool MyData;
friend class boost::archive::detail::common_oarchive<MyOArchive>;
friend class basic_text_oarchive<MyOArchive>;
friend class boost::archive::save_access;
MyOArchive(std::ostream &os, unsigned int flags = 0) : boost::archive::text_oarchive_impl<MyOArchive>(os, flags) {}
};
class MyClass {
private:
friend class boost::serialization::access;
double Value;
template <class Archive> void serialize(Archive &ar, unsigned) { ar &Value; }
};
int main() {
MyClass myClass;
{
std::ofstream outputStream("test.txt");
MyOArchive outputArchive(outputStream);
outputArchive << myClass;
}
}
The output is
22 serialization::archive 13 0 0 6.95328877045326431e-310

Related

Boost XML archiving compiling error with polymorphic classes

I am trying to save my files in XML format using boost archiving.
I get these two errors at compile time.
Error C2664 'int boost::mpl::assertion_failed(boost::mpl::assert::type)': cannot convert argument 1 from 'boost::mpl::failed ***********boost::serialization::is_wrapper:: ***********' to 'boost::mpl::assert::type'
Error C2789 'mpl_assertion_in_line_6': an object of const-qualified type must be initialized
This happens because of these two lines.
BOOST_CLASS_EXPORT_GUID(SumKeyframeXYZ, "SumKeyframeXYZ")
BOOST_CLASS_EXPORT_GUID(SumPosition_Channel, "SumPosition_Channel")
This is the Main function.
#include "Container.h"
BOOST_CLASS_EXPORT_GUID(SumKeyframeXYZ, "SumKeyframeXYZ")
BOOST_CLASS_EXPORT_GUID(SumPosition_Channel, "SumPosition_Channel")
int main()
{
std::ofstream ofs("D:\\output.xml");
Container cont;
cont.AddPositionChannel();
boost::archive::xml_oarchive oa(ofs);
oa << BOOST_SERIALIZATION_NVP(cont);
return 0;
}
This is how the classes structure looks like.
Container.h
#include <string>
#include "SumChannel.h"
#include "SumPosition_Channel.h"
#include <fstream>
#include <iostream>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/shared_ptr.hpp>
class Container
{
private:
std::string stdstrName;
std::vector<std::shared_ptr<SumChannel>> Channels;
public:
Container() { stdstrName = "Container Name"; }
void AddPositionChannel() {
std::shared_ptr< SumPosition_Channel> posChannel = std::make_shared<SumPosition_Channel>();
Channels.push_back(posChannel);
};
private:
friend class boost::serialization::access;
template<class Archive> void serialize(Archive & ar,
const unsigned int version) const {
ar & BOOST_SERIALIZATION_NVP(stdstrName);
ar & BOOST_SERIALIZATION_NVP(Channels);
}
};
//////////////////////////////////////////////////////////
SumChannel.h
#include <fstream>
#include <iostream>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/vector.hpp>
class SumChannel
{
public:
float offset;
SumChannel() { offset = 1.0; }
private:
friend class boost::serialization::access;
template<class Archive> void serialize(Archive & ar,
const unsigned int version) const {
ar & BOOST_SERIALIZATION_NVP(offset);
}
};
SumPosition_Channel
#include "SumKeyframeXYZ.h"
#include "SumChannel.h"
#include <vector>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/vector.hpp>
class SumPosition_Channel : public SumChannel
{
public:
std::vector<SumKeyframeXYZ> keyframes;
void AddKeyframe() { SumKeyframeXYZ key; keyframes.push_back(key); }
private:
friend class boost::serialization::access;
typedef SumChannel _Super;
template<class Archive> void serialize(Archive & ar,
const unsigned int version) const {
ar & boost::serialization::base_object<_Super>(*this);
ar & BOOST_SERIALIZATION_NVP(keyframes);
}
};
KeyFrameBase.h
#include <iostream>
#include <fstream>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
class Keyframebase
{
public:
std::string stdstrName;
float time;
Keyframebase() { stdstrName = "BaseKey"; time = 50.0; }
private:
friend class boost::serialization::access;
template<class Archive> void serialize(Archive & ar,
const unsigned int version) {
ar & BOOST_SERIALIZATION_NVP(stdstrName);
ar & BOOST_SERIALIZATION_NVP(time);
}
};
SumKeyframeXYZ.h
#include "KeyframeBase.h"
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/vector.hpp>
class SumKeyframeXYZ : public Keyframebase
{
public:
float x;
float y;
float z;
SumKeyframeXYZ() { x = 150.0; y = 200.0; z = 300.0; }
private:
friend class boost::serialization::access;
template<class Archive> void serialize(Archive & ar,
const unsigned int version) const {
ar & boost::serialization::base_object<Keyframebase>(*this);
ar & BOOST_SERIALIZATION_NVP(x);
ar & BOOST_SERIALIZATION_NVP(y);
ar & BOOST_SERIALIZATION_NVP(z);
}
};
The issue with the code was that i was not writing NVP to the base class
I changed the Base class archiving code from
ar & boost::serialization::base_object<_Super>(*this);
to this for all the base classes.
typedef SumChannel _Super;
ar & boost::serialization::make_nvp("SumChannel", boost::serialization::base_object<_Super>(*this));
and removed the const from the serilize function.

"unregistered void cast" using boost serialiazation derived to base class

I am on my second attempt to setup polymorphic serialization using the boost library. I am using this as a learning experience, but I may be a little in over my head and I am considering going back to coding the serialization myself rather than boost. Or switch to learning the vistor message Sehe showed me in a previous post.
The issue I am seeing is "unregistered void cast"
I am using shared library linking for the boost serialization library
aTodo.h:
#ifndef ATODO_H
#define ATODO_H
#include <boost/serialization/export.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/unique_ptr.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
class aTodo{
public:
static const unsigned _Type=0x00;
virtual ~aTodo(){};
virtual void Do()=0;
virtual unsigned getInitType(){return _Type;};
private:
friend class boost::serialization::access;
template <class Ar> void serialize(Ar &, unsigned){};
};
#endif
todoExec.h:
#ifndef ATODOEXEC_H
#define ATODOEXEC_H
#include "aTodo.h"
class todoExec : public aTodo{
public:
static const unsigned _TYPE= 0x01;
todoExec(std::string const & command=""):_command(command){};
virtual unsigned getInitType(){return _TYPE;};
virtual void Do(){std::cout << "foo:" << getCommand() << std::endl;};
std::string getCommand() const {return _command;};
protected:
private:
friend class boost::serialization::access;
template <class Archive> void serilize(Archive & ar, unsigned){
boost::serialization::void_cast_register<todoExec,aTodo>();
boost::serialization::base_object<aTodo>(*this);
ar& _command;
}
std::string _command;
};
#endif
todoFactory.h:
#ifndef TODOFACTORY_H
#define TODOFACTORY_H
#include "todoExec.h"
#include <memory>
class todoFactory{
todoFactory()=default;
public:
static std::unique_ptr<todoFactory> create(){return std::move(std::unique_ptr<todoFactory>(new todoFactory));};
//save
static std::string save(std::unique_ptr<aTodo> &todoIn){
std::string out;
{
boost::iostreams::stream<boost::iostreams::back_insert_device<std::string>>os(out);
boost::archive::text_oarchive archive(os);
archive << todoIn;
}
return out;
}
static std::unique_ptr<aTodo> load(std::string const &s ){
std::unique_ptr<aTodo> p;
{
boost::iostreams::stream<boost::iostreams::array_source> is(boost::iostreams::array_source{s.data(),s.size()});
boost::archive::text_iarchive archive(is);
archive >> p;
}
return std::move(p);
}
std::unique_ptr<aTodo> createExec(std::string command) {return std::unique_ptr<aTodo>(new todoExec(command));};
};
#endif
client.cpp
#include <string>
#include <iostream>
#include "todoFactory.h"
BOOST_SERIALIZATION_ASSUME_ABSTRACT(aTodo)
BOOST_CLASS_EXPORT(todoExec)
#include <memory>
int main(void)
{
char mtype=0x01;
std::string dataToSend = "ls -al /home/ajonen";
auto tmpTodoFactory=todoFactory::create(); //create factory
auto anExecTodo=tmpTodoFactory->createExec(dataToSend); //create ExecTodo from factory
std::string toSend= tmpTodoFactory->save(anExecTodo);
return 0;
}
The error I get is:
terminate called after throwing an instance of 'boost::archive::archive_exception'
what(): unregistered void cast 8todoExec<-5aTodo
Aborted
In class todoExec you've got a typo - is: serilize, should be: serialize; therefore the cast is not registered.

how to serialize list of type shared_ptr pointer type using boost serialization

i'm trying to serialize class which has member variable of type like std::list> lss
#include <boost/serialization/optional.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/list.hpp>
struct SomeStruct
{
int x;
double y;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &at, const unsigned int version)
{
at & x;
at & y;
}
};
class BuildTest
{
std::list<boost::shared_ptr<SomeStruct *>> lss ;
std::string name;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &at, const unsigned int version)
{
at & lss; // is this sufficient to serialize lss ?
at & name;
}
}
i have added all required header files for boost serialization. There is similar question but with proper answer how do i serialize list variable of type <boost::shared_ptr<void *>>
You want
std::list<boost::shared_ptr<SomeStruct>> lss ;
Not std::list<boost::shared_ptr<SomeStruct*>>
See it Live On Coliru
#include <boost/serialization/optional.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/list.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/make_shared.hpp>
struct SomeStruct {
int x;
double y;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &at, const unsigned int version) {
at & x;
at & y;
}
};
class BuildTest {
public:
std::list<boost::shared_ptr<SomeStruct>> lss ;
std::string name;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &at, const unsigned int version) {
at & lss; // is this sufficient to serialize lss ?
at & name;
}
};
int main() {
BuildTest bt;
bt.name = "Let's try this";
bt.lss = { boost::make_shared<SomeStruct>(), boost::make_shared<SomeStruct>() };
boost::archive::text_oarchive oa(std::cout);
oa << bt;
}

Boost serilaization with shared pointer and templates

I'm new to C++ and how do i serialize the struct having shared pointer and template .
Below is sample code.
#pragma once
#include <boost/serialization/access.hpp>
#include <boost\serialization\string.hpp>
#include <boost\serialization\shared_ptr.hpp>
//Mydata.hpp file
namespace mydata
{
struct MyData
{
std::string name;
std::string type;
std::shared_ptr<MyInfo> myref;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &ar, const unsigned int vs)
{
ar & name;
ar & type;
ar & myref;
}
}
}
now how do i implement in the corresponding Mydata.cpp file for shared pointer ?
That header includes support for boost::shared_ptr, so the following works:
#include <boost/serialization/access.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/smart_ptr/make_shared.hpp>
namespace mydata
{
struct MyInfo
{
std::string info = "extra info";
MyInfo(std::string info) : info(std::move(info)) {}
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &ar, const unsigned int /*version*/)
{
ar & info;
}
};
struct MyData
{
std::string name;
std::string type;
boost::shared_ptr<MyInfo> myref;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &ar, const unsigned int /*version*/)
{
ar & name;
ar & type;
ar & myref;
}
};
}
int main()
{
using namespace mydata;
MyData data { "this is a name", "this is a type", boost::make_shared<MyInfo>("this is info") };
boost::archive::text_oarchive oa(std::cout);
oa << data;
}
See it Live On Coliru

Boost::serialization and boost::mpi to broadcast derived class via base class pointer

I am trying to use boost::mpi::broadcast to send a derived class to all nodes via a base class pointer. To do this, I am using the boost::serialization library to serialize my classes. My code, however, does not compile and I get the errors "class boost::mpi::packed_skeleton_iarchive’ has no member named ‘append’" and "class boost::mpi::packed_skeleton_iarchive’ has no member named ‘reset’."
Here is the rough source code for the program:
// Base.hpp
#include <boost/serialization/serialization.hpp>
class Base
{
public:
Base() {}
virtual ~Base() {}
virtual void foo() = 0;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize( Archive& /*ar*/, const unsigned int /*version*/ ) {}
}
// Derived.hpp
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
#include "Base.hpp"
class Derived : public Base
{
public:
Derived( int param );
virtual ~Derived();
void foo();
private:
int param_;
std::vector< boost::shared_ptr > bar_;
friend class boost::serialization::access;
template<class Archive>
void serialize( Archive& ar, const unsigned int /*version*/ )
{
ar & param_;
ar & bar_;
ar & boost::serialization::base_object< Base >( *this );
}
}
namespace boost
{
namespace serialization
{
template<class Archive>
void load_construct_data( Archive& /*ar*/, Derived* d,
const unsigned int /*v*/ )
{
::new(d) Derived( 0 );
}
}
}
BOOST_CLASS_EXPORT_KEY( Derived )
// Derived.cpp
#include "Derived.hpp"
Derived::Derived( int param ) : param_( param ) {}
Derived::~Derived(){}
Derived::foo()
{
// some stuff
}
BOOST_CLASS_EXPORT_IMPLEMENT( Derived )
// Main.cpp
#include <boost/mpi.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/shared_ptr.hpp>
#include "Derived.hpp"
int main( int argc, char* argv[] )
{
boost::shared_ptr< Base > sp;
if ( world.rank() == 0 )
{
sp = boost::shared_ptr< Base >( new Derived( 5 ) );
boost::mpi::broadcast( world, sp, 0 );
// produce some stuff
} else
{
while ( 1 )
{
// consume some stuff
}
}
return 0;
}
BOOST_SERIALIZATION_ASSUME_ABSTRACT( Base )
I found only one Google Groups discussion about this problem but no solution so far https://groups.google.com/forum/#!msg/boost-developers-archive/Ee9_ilEDO7s/cJTy-8v5lEcJ. How can I get this to compile? I am using openmpi 1.2.8-17.4, gcc 4.5.1 and boost 1.54.
I was thankfully able to answer my own question (I think.) Boost doesn't handle through-base-pointer serialization properly when combined with boost::mpi::packed_skeleton_iarchive. The solution is then to use a different kind of archive, e.g. text_iarchive/text_oarchive, instead.
For example, to broadcast:
std::ostringstream oss;
boost::archive::text_oarchive oa(oss);
oa << value;
std::string s = oss.str();
boost::mpi::broadcast(comm, s, root);
And to receive:
std::string s;
boost::mpi::broadcast(comm, s, root);
std::istringstream iss(s);
boost::archive::text_iarchive ia(iss);
ia >> value;