Hi,
I have been playing with cereal and am trying to use it for some code
I am writing. Sofar it is a great experience, very nice library!
One thing I prefer to do is keep the serialization logic as much as
possible seperated from the actual types I am working with.
For a simple type, no hierarchy, this works fine.
In the code below I have a class hierarchy of Base <- Derived <- Derived2.
In the case that I implement the code internally to the types,
things work fine. The values are serialized/deserialized properly.
However when I try to write the serialization code
as an external serialize function, I get compile errors.
I'm a bit at loss what I am missing. Looking at base_class.hpp,
base_class takes a const Base * pointer, but the Base passed into the
serialize function should not be const, I would expect. So that gives
the error. But how to solve this then ?
Maybe I have overlooked something in the documentation,
but if someone has some hints on what I m doing wrong, it would be greatly appreciated.
Thanks
Jiri
System:
$ uname -a
Darwin JiriMBP.home 14.4.0 Darwin Kernel Version 14.4.0: Thu May 28 11:35:04 PDT 2015; root:xnu-2782.30.5~1/RELEASE_X86_64 x86_64 i386 MacBookPro11,2 Darwin
$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.4.0
Thread model: posix
Error:
```
/Users/Jiri/sandbox/cereal/testCereal.cpp:301:42: error: no matching conversion for functional-style cast from 'Derived' to
'cereal::base_class<Base>'
ar( cereal::make_nvp( "Derived", cereal::base_class<Base>( d ) ),
^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/cereal/types/base_class.hpp:72:12: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Derived'
to 'const cereal::base_class<Base>' for 1st argument
struct base_class : private traits::detail::BaseCastBase
^
/usr/local/include/cereal/types/base_class.hpp:72:12: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'Derived'
to 'cereal::base_class<Base>' for 1st argument
struct base_class : private traits::detail::BaseCastBase
^
/usr/local/include/cereal/types/base_class.hpp:75:9: note: candidate template ignored: could not match 'const Derived *' against 'Derived'
base_class(Derived const * derived) :
^
```
Code:
```
#include <gtest/gtest.h>
#include <cereal/archives/binary.hpp>
#include <cereal/archives/xml.hpp>
#include <cereal/archives/json.hpp>
#include <cereal/cereal.hpp>
#include <cereal/types/base_class.hpp>
#include <cereal/types/polymorphic.hpp>
#include <cereal/types/common.hpp>
#include <fstream>
#include <sstream>
// if INTERNAL is undefined, compile errors pop up.
#define INTERNAL 1
struct Base
{
int x;
virtual int doSomething() const = 0;
virtual ~Base() {}
#ifdef INTERNAL
template <class Archive>
void serialize( Archive& ar )
{
ar( cereal::make_nvp( "x", x ) );
}
#else
template <class Archive>
friend void cereal::serialize( Archive& ar, Base& b );
#endif
};
struct Derived : public Base
{
int y;
int doSomething() const override { return 1; }
#ifdef INTERNAL
template <class Archive>
void serialize( Archive& ar )
{
ar( cereal::make_nvp( "Derived", cereal::base_class<Base>( this ) ),
cereal::make_nvp( "y", y ) );
}
#else
template <class Archive>
friend void cereal::serialize( Archive& ar, Derived& d );
#endif
};
struct Derived2 : public Derived
{
int z;
int doSomething() const override { return 2; }
#ifdef INTERNAL
template <class Archive>
void serialize( Archive& ar )
{
ar( cereal::make_nvp( "Derived2", cereal::base_class<Derived>( this ) ),
cereal::make_nvp( "z", z ) );
}
#else
template <class Archive>
friend void cereal::serialize( Archive& ar, Derived2& d );
#endif
};
#ifndef INTERNAL
namespace cereal
{
template <class Archive>
void serialize( Archive& ar, Base& b )
{
ar( cereal::make_nvp( "x", b.x ) );
}
template <class Archive>
void serialize( Archive& ar, Derived& d )
{
ar( cereal::make_nvp( "Derived", cereal::base_class<Base>( d ) ),
cereal::make_nvp( "y", d.y ) );
}
template <class Archive>
void serialize( Archive& ar, Derived2& d )
{
ar( cereal::make_nvp( "Derived2", cereal::base_class<Derived>( d ) ),
cereal::make_nvp( "z", d.z ) );
}
} // namespace cereal
#endif
TEST( Cereal, TestInheritance )
{
std::string dir( "." );
{
std::ofstream ofileJSON( dir + "/out.json" );
std::ofstream ofileXML( dir + "/out.xml" );
cereal::JSONOutputArchive oarchiveJSON( ofileJSON );
cereal::XMLOutputArchive oarchiveXML( ofileXML );
Derived d;
d.x = 1234;
d.y = 9876;
Derived2 d2;
d2.x = 1234;
d2.y = 9876;
d2.z = 1199;
oarchiveJSON(
cereal::make_nvp( "d", d ),
cereal::make_nvp( "d2", d2 ) );
oarchiveXML(
cereal::make_nvp( "d", d ),
cereal::make_nvp( "d2", d2 ) );
}
{
std::ifstream ifileJSON( dir + "/out.json" );
cereal::JSONInputArchive iarchiveJSON( ifileJSON ); // Create an input archive
Derived d;
Derived2 d2;
iarchiveJSON( d, d2 );
// auto options = cereal::JSONOutputArchive::Options::NoIndent();
auto options = cereal::JSONOutputArchive::Options( 6 );
std::ostream& os( std::cout );
cereal::JSONOutputArchive oarchiveJSON2( os, options );
oarchiveJSON2(
cereal::make_nvp( "d", d ),
cereal::make_nvp( "d2", d2 ) );
}
}
```