Serialization Boost: Reading Different Data Types

I have a C ++ / CLI project that uses boost serialization to serialize three different classes. I would like to know if it is possible to parse the first line of a serial archive to find out which class was serialized in that archive, and then create an object of the corresponding class and deserialize the archive in the object. This string will contain an identifier (perhaps an int or an enum class value) to determine which class was serialized.

+3


source to share


1 answer


The file format is already processed according to your choice of the archive implementation.

In practice it will boost::archive::text_oarchive

, boost::archive::binary_oarchive

, boost::archive::xml_oarchive

.

As long as your archive type doesn't change, you can very easily use the Boost variant to differentiate your payloads. In other words, make the serialization framework a job done for you, rather than "channeling" around it:

Here's a demo that serializes 3 different (composite) useful and useful routes just fine, with no external knowledge of the payload actually:



Live On Coliru

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <boost/serialization/variant.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/string.hpp>

#include <boost/serialization/access.hpp>

struct A {
    int simple;

  private:
    friend class boost::serialization::access;
    template <typename Ar> void serialize(Ar& ar, unsigned) {
        ar & simple;
    }
};

struct B {
    std::string text;

  private:
    friend class boost::serialization::access;
    template <typename Ar> void serialize(Ar& ar, unsigned) {
        ar & text;
    }
};

struct C {
    A composed_a;
    B composed_b;

  private:
    friend class boost::serialization::access;
    template <typename Ar> void serialize(Ar& ar, unsigned) {
        ar & composed_a & composed_b;
    }
};

struct FileContents { // conventions...
    boost::variant<A, B, C> payload;

  private:
    friend class boost::serialization::access;
    template <typename Ar> void serialize(Ar& ar, unsigned) {
        ar & payload;
    }
};


#include <sstream>
#include <boost/lexical_cast.hpp>

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// For our roundtrip test, implement streaming as well so we can independently check equivalence
inline static std::ostream& operator<<(std::ostream& os, A const& v) {
    return os << "A{" << v.simple << "}";
}
inline static std::ostream& operator<<(std::ostream& os, B const& v) {
    return os << "B{" << v.text << "}";
}
inline static std::ostream& operator<<(std::ostream& os, C const& v) {
    return os << "C{" << v.composed_a << ", " << v.composed_b << "}";
}

void roundtrip_test(FileContents const& original) {
    std::stringstream ss;
    {
        boost::archive::text_oarchive oa(ss);
        oa << original;
    }

    {
        boost::archive::text_iarchive ia(ss);

        FileContents clone;
        ia >> clone;

        std::string const before = boost::lexical_cast<std::string>(original.payload);
        std::string const after  = boost::lexical_cast<std::string>(clone.payload);

        std::cout << "Roundtrip '" << before << "': " << std::boolalpha << (before == after) << "\n";
    }
}

int main() {
    roundtrip_test({ A { 42 } });
    roundtrip_test({ B { "Life The Universe And Everything" } });
    roundtrip_test({ C { {42}, { "Life The Universe And Everything" } } });
}

      

Output:

Roundtrip 'A{42}': true
Roundtrip 'B{Life The Universe And Everything}': true
Roundtrip 'C{A{42}, B{Life The Universe And Everything}}': true

      

+2


source







All Articles