简体   繁体   English

C ++ - boost ::任何序列化

[英]C++ - boost::any serialization

As far as I understand, there is no serialization ( boost::serialization , actually) support for boost::any placeholder. 据我所知,没有序列化( boost::serialization ,实际上)支持boost::any占位符。

Does someone know if there is a way to serialize a custom boost::any entity? 有人知道是否有办法序列化自定义boost::any实体?

The problem here is obvious: boost::any uses template-based placeholders to store objects and typeid to check if boost::any_cast is appropriate. 这里的问题很明显: boost::any使用基于模板的占位符来存储对象和typeid来检查boost::any_cast是否合适。

So, there is a custom abstract superclass placeholder and custom template-based derived classes, which are created the following way: 因此,有一个自定义抽象超类placeholder和基于自定义模板的派生类,它们按以下方式创建:

template <T> custom_placeholder : public placeholder {
    virtual std::type_info type() const { return typeid(T); }
    virtual ...
};

Obviously, this brings some troubles when even thinking about serializing this stuff. 显然,即使考虑序列化这些东西,这也会带来一些麻烦。 Maybe someone knows some trick to make such kind of serialization (and of course, proper deserialization)? 也许有人知道做这种序列化的一些技巧(当然还有正确的反序列化)?

Thank you 谢谢

If you want to stick with boost::any i am not sure but you can write your own "boost::any". 如果你想坚持使用boost ::任何我不确定但你可以编写自己的“boost :: any”。 I'm using this code for proxy methods to pass the parameters. 我正在使用此代码来代理方法来传递参数。

#include <iostream>
#include <boost\smart_ptr\scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/export.hpp>
#include <sstream>
class my_placeholder
{
public:
    virtual ~my_placeholder(){}
    my_placeholder(){}
private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        // serialize base class information
        //ar & boost::serialization::base_object<bus_stop>(*this);
        //ar & m_placeholder;

    }

};




template<typename T>
class my_derivedplaceholder:
    public my_placeholder
{
    public:
        my_derivedplaceholder()
        {

        }
        my_derivedplaceholder(T &value)
        {
            m_value=value;
        }
    T m_value;

private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        // serialize base class information
        ar & boost::serialization::base_object<my_placeholder>(*this);
        ar & m_value;

    }
};


BOOST_CLASS_EXPORT_GUID(my_derivedplaceholder<int>, "p<int>");


class my_any
{
public:

    my_any()
    {

    }

    template<typename T>
    my_any(const T &value)
    {
        m_placeholder.reset(new my_derivedplaceholder<T>(const_cast<T&>(value)));
    }

    template<typename T>
    void operator=(const T &value)
    {
        m_placeholder.reset(new my_derivedplaceholder<T>(const_cast<T&>(value)));
    }



protected:

    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        // serialize base class information
        //ar & boost::serialization::base_object<bus_stop>(*this);
        ar & m_placeholder;

    }

     template<typename T>
    friend    T my_anycast(my_any &val);

    boost::shared_ptr<my_placeholder> m_placeholder;
};

template<typename T>
T my_anycast(my_any &val)
{
    boost::shared_ptr<my_derivedplaceholder<T>> concrete=boost::dynamic_pointer_cast<my_derivedplaceholder<T>>(val.m_placeholder);
    if (concrete.get()==NULL)
        throw std::invalid_argument("Not convertible");

    return concrete->m_value;
}

void main()
{
    my_any m=10;

    int a=my_anycast<int>(m);

    std::cout << a << std::endl;

    std::stringstream ss,ss2;
    boost::archive::text_oarchive oa(ss);

    oa << m;

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

    my_any m2;
    ia >> m2;

    std::cout << my_anycast<int>(m2) << std::endl;
}

It is not possible at all, at least for arbitrary types. 完全不可能,至少对于任意类型。 Note that maybe you could serialize using some tricky code (like finding the size of the elements contained in the any), but the any code relies on the compiler statically putting the any type_code and the proper types inside the placeholder. 请注意,也许您可​​以使用一些棘手的代码进行序列化(比如查找any中包含的元素的大小),但是任何代码都依赖于编译器静态地将任何type_code和正确的类型放在占位符中。 You surely cannot do that in deserialization in C++, as the type that you'd get from the deserialization is not known at compile time (as required by the newly formed boost::any ). 你肯定不能在C ++中反序列化那样做,因为你在反编译时得到的类型在编译时是不知道的(按照新形成的boost::any )。

The best solution is to build some kind of specialized any type for the exact types of elements you're going to serialize. 最好的解决方案是为您要序列化的元素的确切类型构建某种专用的任何类型。 Then, you can have special cases for the actual type of element being deserialized, but note that each element type serialization/deserialization has to be phisically written as static C++ code. 然后,您可以对要反序列化的元素的实际类型有特殊情况,但请注意,每个元素类型序列化/反序列化必须在逻辑上写为静态C ++代码。

PD. PD。 Some others suggested using boost::variant as a representation of this specialized type holding the exact types you're going to serialize. 其他一些人建议使用boost::variant作为这种特殊类型的表示,其中包含您要序列化的确切类型。 You need a way of discerning the exact type on deserialization, though (maybe assigning identifiers to types in the variant). 但是,您需要一种方法来识别反序列化的确切类型(可能为变体中的类型指定标识符)。

There is no need to create new class. 无需创建新类。 Try to use xany https://sourceforge.net/projects/extendableany/?source=directory xany class allows to add new methods to any's existing functionality. 尝试使用xany https://sourceforge.net/projects/extendableany/?source=directory xany类允许向任何现有功能添加新方法。 By the way there is a example in documentation which does exactly what you want. 顺便提一下,文档中有一个例子可以完全满足您的需求。

Assuming you have to use boost::any and you cannot switch to variant , a map<type_info const*, string(*)(any)> based solution could get you done. 假设您必须使用boost::any并且无法切换到variant ,则基于map<type_info const*, string(*)(any)>的解决方案可以帮助您完成。

You have to initialize at runtime such a map with all the types you plan to use. 您必须在运行时初始化此类map ,其中包含您计划使用的所有类型。 Of course, you can use something along the lines of 当然,你可以使用一些东西

template <typename T>
struct any_serializer
{
    static string perform(any a)
    {
        T const& x = any_cast<T const&>(a);
        stringstream out;
        out << x;
        return out.str();
    }
};

and populate the map with addresses of any_serializer<T>::perform under the key &typeid(T) . 并在key &typeid(T)下填充地址为any_serializer<T>::perform的地图。 You can specialize the class any_serializer and use some (ugly) macros to populate the map. 您可以专门化类any_serializer并使用一些(丑陋的)宏来填充地图。

More difficult is of course the deserialization. 更难的当然是反序列化。 I haven't had a look at boost::lexical_cast for a while, perhaps it can provide some help. 我有一段时间没看过boost::lexical_cast ,也许它可以提供一些帮助。 I am afraid that this is totally problem-dependant. 我担心这完全依赖于问题。 However, you only need one function, which takes a string and returns one any . 但是,您只需要一个函数,它接受一个string并返回any一个。 You may also want to prepend your output string with a custom type identifier. 您可能还希望在输出字符串前加上自定义类型标识符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM