C++ - boost::any serialization

淺唱寂寞╮ 提交于 2019-11-30 17:47:55

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. 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).

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.

PD. Some others suggested using boost::variant as a representation of this specialized type holding the exact types you're going to serialize. You need a way of discerning the exact type on deserialization, though (maybe assigning identifiers to types in the variant).

If you want to stick with boost::any i am not sure but you can write your own "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;
}

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.

You have to initialize at runtime such a map with all the types you plan to use. 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). You can specialize the class any_serializer and use some (ugly) macros to populate the map.

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. I am afraid that this is totally problem-dependant. However, you only need one function, which takes a string and returns one any. You may also want to prepend your output string with a custom type identifier.

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. By the way there is a example in documentation which does exactly what you want.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!