How to serialize a boost::uuid with cereal

1k Views Asked by At

Trying to serialize this simple class:

class Data
{
public:
    Data();
    Data(boost::uuids::uuid id);

    Data(const Data&) = delete;
    Data& operator=(const Data&) = delete;

    inline boost::uuids::uuid getGuid() { return guid; }

    template <class Archive>
    void serialize(Archive & ar)
    {
        ar(guid);
    }

private:
    boost::uuids::uuid guid;
};

But I get this error message

error C2338: Trying to serialize an unserializable type with an output archive. 

Poiting to the uuid. The boost serialization way to enable this would be to add

#include <boost/uuid/uuid_serialize.hpp>

but this doesn't work for cereal out of the box. Cereal documentation says

cereal archives operate on either an std::ostream or std::istream object.

so I tried adding the header where there are defined but no luck

#include <boost/uuid/uuid_io.hpp>
2

There are 2 best solutions below

0
On BEST ANSWER

This worked with cereal JSON archives. I also included in comment a way to do it for a binary archive.

#ifndef CEREAL_TYPES_BOOST_UUID_
#define CEREAL_TYPES_BOOST_UUID_

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/lexical_cast.hpp>

namespace cereal
{
    template <class Archive> inline
        void save(Archive& ar, boost::uuids::uuid const& uuid)
    {
        std::string val = boost::lexical_cast<std::string>(uuid);

        ar(val);

        // Other approach, probably better for binary
        //ar(make_size_tag(static_cast<size_type>(uuid.size())));
        //for (auto it = uuid.begin(), end = uuid.end(); it != end; ++it)
        //  ar(*it);
    }

    template <class Archive> inline
        void load(Archive& ar, boost::uuids::uuid& uuid)
    {
        std::string val;

        ar(val);
        uuid = boost::lexical_cast<boost::uuids::uuid>(val);

        // Other approach, probably better for binary
        //size_type size;
        //ar(make_size_tag(size));

        //for (auto it = uuid.begin(), end = uuid.end(); it != end; ++it) {
        //  uint8_t val;
        //  ar(val);
        //  *it = val;
        //}
    }
} // namespace cereal

#endif // CEREAL_TYPES_BOOST_UUID_
3
On

The fact that

cereal archives operate on either an std::ostream or std::istream object.

doesn't (at all) imply that it using the IO streaming operators (>>, <<). That's just the archive implementation.

You'll have to implement the free function serialize to let Cereal know about your type. You should be able to reuse the implementation shown in uuid_serialize.hpp. Chances are you should simply

  • move those definitions into the cereal namespace (preferrably) or into the boost::uuids namespace (might conflict in the future) for ADL to find them
  • best to treat the UUIDs as simple arrays of bytes (AFAIR boost::uuids::uuid is a POD data type)