I'm trying to serialize a pointer to a polymorphic class Shape
. So I need to use the BOOST_CLASS_EXPORT
macro to define a GUID for each subclass. The problem: where to put it?
Let me show a minimal test case first:
shapes.hpp
#include <boost/serialization/access.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
class Shape {
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive &ar, unsigned int const version) {
// nothing to do
}
public:
virtual ~Shape() { }
};
class Rect : public Shape {
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive &ar, unsigned int const version) {
ar & boost::serialization::base_object<Shape>(*this);
}
public:
virtual ~Rect() { }
};
#ifdef EXPORT_IN_HEADER
BOOST_CLASS_EXPORT(Rect)
#endif
export.cpp
#include <boost/serialization/export.hpp>
#include "shapes.hpp"
#ifdef EXPORT_IN_OBJECT
BOOST_CLASS_EXPORT(Rect)
#endif
main.cpp
#include <iostream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/export.hpp>
#include "shapes.hpp"
#ifdef EXPORT_IN_MAIN
BOOST_CLASS_EXPORT(Rect)
#endif
int main() {
Shape *shape = new Rect();
boost::archive::text_oarchive ar(std::cout);
ar << shape;
}
On gcc, I compile these with
g++ -omain main.cpp export.cpp -Wl,-Bstatic -lboost_serialization-mt -Wl,-Bdynamic -DEXPORT_IN_XXX
Here, export.cpp
may look a bit silly. In my actual situation, it contains an enclosing class that uses the PIMPL idiom, and tries to serialize its (polymorphic) Shape
implementation. The important point is: the BOOST_CLASS_EXPORT
could be in a different object file than the code that invokes the serialization.
So here's the problem: where to use BOOST_CLASS_EXPORT
? I have three options, which can be enabled using the EXPORT_IN_XXX
macros.
EXPORT_IN_MAIN
works, but is not what I want. The code invoking the serialization should not need to know about the implementation details of the PIMPL class.
EXPORT_IN_OBJECT
compiles, but does not work: it results in a boost::archive::archive_exception
with the message unregistered void cast
. According to the documentation, this should be solved by serializing base classes using boost::serialization::base_object
, like I did, but it doesn't help.
EXPORT_IN_HEADER
does not even compile. The macro BOOST_CLASS_EXPORT
expands to a template specialization (which we'd like to be in the header file), but also to the definitiof of a static member therein. So I get a linker error about a multiple definition of 'boost::archive::detail::init_guid<Rect>::guid_initializer'
.
If it matters, I'm using g++ 4.4.3 and Boost 1.40.
Exporting Class Serialization of the Boost.Serialization docs (1.44.0) states the following:
BOOST_CLASS_EXPORT
in the same source module that includes any of the archive class headers will instantiate code [...]Note that the implemenation of this functionality requires that the
BOOST_CLASS_EXPORT
macro appear after and the inclusion of any archive class headers for which code is to be instantiated. So, code that usesBOOST_CLASS_EXPORT
will look like the following:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
... // other archives
#include "a.hpp" // header declaration for class a
BOOST_CLASS_EXPORT(a)
... // other class headers and exports
[...] Including
BOOST_CLASS_EXPORT
in the "a.hpp" header itself as one would do with other serialization traits will make it difficult or impossible to follow the rule above regarding inclusion of archive headers beforeBOOST_CLASS_EXPORT
is invoked. This can best be addressed by usingBOOST_CLASS_EXPORT_KEY
in the header declarations andBOOST_CLASS_EXPORT_IMPLEMENT
in the class definition file.