提升序列化:读取不同类型的数据

Boost serialization : read varying type of data

我有一个 C++/CLI 项目,它使用 boost 序列化来序列化三个不同的 classes。我想知道是否可以解析 boost 序列化存档的第一行,以便知道在这个存档中序列化了什么 class,然后创建一个适当的 class 的对象并反序列化归档到对象中。该行将包含一个 ID(可能是一个 int 或枚举 class 的值)以标识哪个 class 被序列化。

文件格式已由您选择的存档实现处理。

实际上是 boost::archive::text_oarchiveboost::archive::binary_oarchiveboost::archive::xml_oarchive

只要您的存档类型本身没有变化,您就可以非常轻松地使用 Boost Variant 来区分您的有效负载。换句话说,让序列化框架为您完成工作,而不是 "duct taping" 围绕它:

这是一个序列化 3 种不同(复合)有效载荷和往返的演示,无需实际有效载荷的外部知识:

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" } } });
}

输出为:

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