Регистрация предоставленных пользователем производных типов с помощью Boost Serialization

Я пишу библиотеку, которая будет хранить и сериализовать пользовательские типы. Определяемые пользователем типы должны быть сериализуемыми.

Однако библиотека использует шаблоны для создания контейнеров пользовательских типов. Я не знаю, как экспортировать типы контейнеров для boost::serialization через шаблоны. Единственный способ, которым я могу это сделать, - заставить пользователя библиотеки использовать BOOST_CLASS_EXPORT_GUID() для каждого типа контейнера.

Я попытался распаковать макрос, просмотрев файл boost/serialization/export.hpp, но он немного сложен... Есть ли способ экспортировать класс как часть создания экземпляра шаблона? Или другой способ написать библиотеку для простой сериализации контейнеров пользовательских типов?

#include <iostream>
#include <vector>

#include <boost/foreach.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>

#include <boost/archive/text_oarchive.hpp>

//////////////////////////////////////////////////////////////////////////////
// Example code that would reside in the library
//////////////////////////////////////////////////////////////////////////////

struct type_container_base {
private:
    virtual void make_abstract() const {}
    friend class ::boost::serialization::access;
    template <typename ARCHIVE>
    void serialize(ARCHIVE &, const unsigned int) {}    
};

BOOST_SERIALIZATION_ASSUME_ABSTRACT(type_container_base)

template <typename USER_TYPE>
struct type_container : type_container_base {
    void add(const USER_TYPE& d) { _vector.push_back(d); }
private:
    std::vector<USER_TYPE> _vector;
    friend class ::boost::serialization::access;
    template <typename ARCHIVE>
    void serialize(ARCHIVE & ar, const unsigned int) {
        ar & ::boost::serialization::base_object<type_container_base>(*this);
        ar & _vector;
    }
};

//////////////////////////////////////////////////////////////////////////////
// Example user code that would use the library
//////////////////////////////////////////////////////////////////////////////

struct user_type {
    user_type(int i) : _val(i) {}
private:
    int _val;
    friend class ::boost::serialization::access;
    template <typename ARCHIVE>
    void serialize(ARCHIVE & ar, const unsigned int) {
        ar & _val;
    }
};

// *** Is there a better way than forcing the user to do this for every
// *** user_type they want to use with the library?
BOOST_CLASS_EXPORT_GUID(type_container<user_type>, "type_container<user_type>")

int main() {
    std::vector<type_container_base*> containers;
    type_container<user_type>* tc = new type_container<user_type>();
    tc->add(user_type(7));
    tc->add(user_type(42));
    tc->add(user_type(1776));
    containers.push_back(tc);
    {
        boost::archive::text_oarchive ar(std::cout);
        const std::size_t size = containers.size();
        ar << size;
        BOOST_FOREACH(type_container_base* p, containers)
            ar << p;
    }
    return 0;
}

person vsekhar    schedule 09.02.2011    source источник


Ответы (1)


Может быть, что-то в этом духе:

#define BOOST_CLASS_TEMPLATE_EXPORT_IMPLEMENT(T)             \
    namespace boost {                                        \
    namespace archive {                                      \
    namespace detail {                                       \
    namespace {                                              \
    template<typename U>                                     \
    struct init_guid< T<U> > {                               \
        static guid_initializer< T<U> > const & g;           \
    };                                                       \
    template<typename U>                                     \
    guid_initializer< T<U> > const & init_guid< T<U> >::g =  \
        ::boost::serialization::singleton<                   \
            guid_initializer< T<U> >                         \
        >::get_mutable_instance().export_guid();             \
    }}}}                                                     \
/**/

#define BOOST_CLASS_TEMPLATE_EXPORT_KEY2(T, K) \
namespace boost {                              \
namespace serialization {                      \
template<typename U>                           \
struct guid_defined< T<U> > : boost::mpl::true_ {}; \
template<typename U>                           \
inline const char * guid< T<U> >(){            \
    return K + "<" + guid<U>() + ">"; //this doesn't work, I know! \
}                                              \
} /* serialization */                          \
} /* boost */                                  \
/**/

#define BOOST_CLASS_TEMPLATE_EXPORT_KEY(T)                             \
    BOOST_CLASS_TEMPLATE_EXPORT_KEY2(T, BOOST_PP_STRINGIZE(T))                                                         \
/**/

#define BOOST_CLASS_TEMPLATE_EXPORT_GUID(T, K)                         \
BOOST_CLASS_TEMPLATE_EXPORT_KEY2(T, K)                                 \
BOOST_CLASS_TEMPLATE_EXPORT_IMPLEMENT(T)                               \
/**/

Это может работать с некоторыми дополнительными настройками. Конечно, предполагается, что user_type уже экспортирован. Но, тем не менее, это уменьшит комбинаторное измерение, все, что вам нужно, это один экспорт для каждого класса и один экспорт для каждого шаблона класса, а не один экспорт для каждого экземпляра шаблона (количество классов X количество шаблонов классов).

Это, вероятно, то, что следует спросить / запросить / предложить парню, отвечающему за библиотеку Boost.Serialization (я думаю, это будет Роберт Рэми).

person Mikael Persson    schedule 09.02.2011
comment
Хм... может там что-то есть. Просто чтобы уточнить, моя проблема заключается не в экспорте типов контейнеров, а в том, что я не могу экспортировать тип, который является специализацией шаблона, параметр которого еще не известен. Это связано с тем, что макросы BOOST_... работают в области пространства имен, поэтому мне нужно, чтобы пользователь обрабатывал экспорт своих типов (и/или связанных типов контейнеров). Принимая во внимание, что я хочу, чтобы библиотека справилась с этим, возможно, напрямую подключившись к библиотеке сериализации. - person vsekhar; 10.02.2011