C ++ - boost :: любая сериализация - PullRequest
11 голосов
/ 09 сентября 2010

Насколько я понимаю, нет поддержки сериализации (boost::serialization, собственно) для boost::any заполнителя.

Кто-нибудь знает, есть ли способ сериализации пользовательского объекта boost::any?

Проблема здесь очевидна: boost::any использует шаблонные заполнители для хранения объектов и typeid, чтобы проверить, подходит ли boost::any_cast.

Итак, существует собственный абстрактный суперкласс placeholder и пользовательские производные классы на основе шаблонов, которые создаются следующим образом:

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

Очевидно, что это вызывает некоторые проблемы, когда даже задумывается о сериализации этого материала. Может быть, кто-то знает какой-то трюк для создания такого рода сериализации (и, конечно, правильной десериализации)?

Спасибо

Ответы [ 4 ]

6 голосов
/ 03 марта 2012

Если вы хотите придерживаться boost :: any, я не уверен, но вы можете написать свой собственный «boost :: any». Я использую этот код для прокси-методов для передачи параметров.

#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;
}
5 голосов
/ 09 сентября 2010

Это вообще невозможно, по крайней мере для произвольных типов.Обратите внимание, что, возможно, вы могли бы сериализовать с помощью некоторого хитрого кода (например, найти размер элементов, содержащихся в any), но любой код полагается на то, что компилятор статически помещает любой type_code и надлежащие types в заполнитель,Вы, конечно, не можете сделать это при десериализации в C ++, так как тип, который вы получите от десериализации, не известен во время компиляции (как того требует вновь созданная boost::any).

Лучшее решение - этосоздайте какой-нибудь специализированный тип для точных типов элементов, которые вы собираетесь сериализовать.Затем вы можете иметь особые случаи для фактического типа десериализуемого элемента, но учтите, что сериализация / десериализация каждого типа элемента должна быть физически записана как статический код C ++.

PD.Некоторые другие предложили использовать boost::variant в качестве представления этого специализированного типа, содержащего точные типы, которые вы собираетесь сериализовать.Однако вам нужен способ определения точного типа при десериализации (возможно, присвоение идентификаторов типам в варианте).

1 голос
/ 17 декабря 2012

Нет необходимости создавать новый класс. Попробуйте использовать xany https://sourceforge.net/projects/extendableany/?source=directory Класс xany позволяет добавлять новые методы к любой существующей функциональности. Кстати, в документации есть пример, который делает именно то, что вы хотите.

1 голос
/ 09 сентября 2010

Если вы используете boost::any и не можете переключиться на variant, решение на основе map<type_info const*, string(*)(any)> может помочь вам.

Вы должны инициализировать во время выполнения такую ​​map всеми типами, которые вы планируете использовать.Конечно, вы можете использовать что-то вроде

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

и заполнить карту адресами any_serializer<T>::perform под ключом &typeid(T).Вы можете специализировать класс any_serializer и использовать некоторые (некрасивые) макросы для заполнения карты.

Более сложная, конечно, десериализация.Я давно не смотрел на boost::lexical_cast, возможно, он может помочь.Я боюсь, что это полностью зависит от проблем.Однако вам нужна только одна функция, которая принимает string и возвращает одну any.Вы также можете добавить в выходную строку пользовательский идентификатор типа.

...