Получение классов пользовательского архива из boost:: archive:: text_oarchive_impl и boost:: archive:: text_iarchive_impl

Примечание:
Схема архивирования Boost основана на симметричных классах ввода и вывода. Затруднительно писать обо всех из них все время, поэтому я буду использовать ?archive для обозначения как oarchive, так и iarchive.

Резюме:
После изменения базовых классов моих пользовательских архивов от binary_?archive_impl до text_?archive_impl мои пользовательские классы архива больше не "обнаруживаются", когда компилятор создает экземпляры методов serialize(...) в моих других классах.

Фон:
Мое приложение успешно читало и записывало файлы на диск с помощью подклассов binary_?archive_impl (документация и/или комментарии по коду рекомендуют это получить из binary_?archive). Мне нужно было перейти от формата двоичного файла к текстовому формату, поэтому я переключил базовые классы моих собственных архивов на text_?archive_impl. Это когда все взорвалось.

Проблема:
Мои пользовательские классы архивов добавляют функциональность, включая некоторые дополнительные методы, которых нет в базовых классах Boost; эти методы называются в методах serialize(...) во многих моих классах, и они работают нормально. После изменения базовых классов от binary_?archive_impl до text_?archive_impl, я получил ошибки компиляции повсюду, жалуясь, что мои пользовательские методы не существуют в text_?archive. Ну, это очевидное (!!!), но они существуют в моих собственных архивах, и они отлично работали, когда я использовал базовые классы Boost. Какая сделка?

То, что я нашел, и мое временное, но нежелательное решение:
После разрыва моих волос и по кругу в течение дня, это то, что я нашел...

1) Некоторое время назад (Boost 1.34, я считаю) файлы "binary_? archive.hpp" были разделены на "binary_? archive_impl.hpp" и "binary_? archive.hpp" (последний # включил первый). Это не было сделано для "text_? Archive.hpp". (В результате я изменил свое приложение #include lines из "binary_? Archive_impl.hpp" на просто "text_? Archive.hpp".)

2) Если я разделил "text_? archive.hpp" на две части и # включил только заголовки "..._ impl.hpp", все работает. (Но я действительно не хочу изменять мою установку Boost!)

3) Более внимательно посмотрев на эти заголовки и немного поиграв, я обнаружил, что если использовать оригинальные, немодифицированные заголовки и прокомментировать строку

BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::archive::text_oarchive)

(а также для text_iarchive), тогда все снова работает отлично. (Кстати, у меня есть аналогичные строки в моем собственном архиве, чтобы "зарегистрировать" мои пользовательские архивы.)

Тайна и моя дилемма:
A) Почему присутствие этих линий нарушает работу?... и почему их удаление заставляет работать?... и что я мог сломать (не зная об этом)?

B) Почему файлы "text_? archive.hpp" не были разделены вместе с файлами "binary_? archive.hpp" давным-давно? (Разве библиотека сломана? Должна ли она быть исправлена?)

C) Есть ли способ решить это в коде приложения без изменения моей установки Boost?

P.S. Я использую Boost 1.48 и Visual Studio 2010 (64-разрядная версия)
P.P.S. Я полагаю, что все вышеизложенное применимо в равной степени к text_w?archive

Ответ 1

В лучшем случае я могу сказать об ошибке в расширении сериализации. Мы увидим здесь.

A)
 1. Добавление BOOST_SERIALIZATION_REGISTER_ARCHIVE с вашим новым архивом не работает, потому что текстовые архивы по умолчанию уже зарегистрированы - только при регистрации, похоже, разрешено.
 2. Удаление их заставляет его работать, потому что регистрируются только ваши пользовательские классы.
 3. Удалив их, вы нарушили возможность использования текстового архива по умолчанию - ваши классы будут зарегистрированы.

B)
Я уверен, что файлы "text_? Archive.hpp" должны быть разделены, как файлы "binary_? Archive.hpp". Патч повышает кого-либо?

C)
Лучшим решением является отправка патча для увеличения, который разбивает файлы. Для временного решения, вероятно, лучший способ - разместить исправленные файлы локально в вашем проекте до тех пор, пока патч не превратит его в boost.

Ответ 2

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

В моей установке 1.49.0 я также вижу соответствующие файлы реализации для типа текста. Они находятся в формате .ipp в каталоге impl. Временная метка предполагает, что они не были изменены недавно, поэтому они должны быть такими же, как и в 1.48. Это может помочь вам разобраться в проблеме.

По словам Дейва Абрахама, . Файлы ipp должны скрывать реализацию. Не знаете, почему они выбрали разные стили.

---------- + 1 stackoverflow Нет 2936 5 декабря 2009./binary_iarchive_impl.hpp

---------- + 1 stackoverflow Нет 2966 5 декабря 2009./binary_oarchive_impl.hpp

---------- + 1 stackoverflow Нет 1392 25 ноября 2007./detail/basic_archive_impl.hpp

---------- + 1 stackoverflow Нет 3458 20 мая 2009./impl/text_iarchive_impl.ipp

---------- + 1 stackoverflow None 3290 2 июля 2005./impl/text_oarchive_impl.ipp

---------- + 1 stackoverflow Нет 3020 26 июня 2008./impl/text_wiarchive_impl.ipp

---------- + 1 stackoverflow Нет 2244 2 июля 2005./impl/text_woarchive_impl.ipp

Ответ 3

У меня была такая же проблема, связанная с внедрением пользовательского архива для моей библиотеки. Я нашел возможный трюк решения, он работает хорошо, поэтому я поделюсь с вами:

Невозможно экспортировать класс с модифицированным синтаксисом синтаксиса в boost-архив, поэтому мы должны его вообще избегать.

boost archive registration использует правильно перегруженную функцию для создания экземпляра типа сериализации указателя (как в boost/archive/detail/register_archive.hpp)

# define BOOST_SERIALIZATION_REGISTER_ARCHIVE(Archive)                  \
namespace boost { namespace archive { namespace detail {                \
                                                                        \
template <class Serializable>                                           \
BOOST_DEDUCED_TYPENAME _ptr_serialization_support<Archive, Serializable>::type  \
instantiate_ptr_serialization( Serializable*, Archive*, adl_tag );              \
                                                                        \
}}}

Обратите внимание, что adl_tag добавляет классную функцию перегрузки, которая может быть использована для повышения возможности поиска внутри нашей реализации. Просто введите новую регистрационную декларацию следующим образом:

// ARCHIVES REGISTRATION //

namespace MyLib {
struct adl_tag {};
}

namespace boost { namespace archive { namespace detail {
template <class Serializable>
void instantiate_ptr_serialization(Serializable*, int, MyLib::adl_tag ) {}
} } }

# define MYLIB_SERIALIZATION_REGISTER_ARCHIVE(_Archive)                   \
namespace boost { namespace archive { namespace detail {                \
template <class Serializable>                                           \
BOOST_DEDUCED_TYPENAME _ptr_serialization_support<_Archive, Serializable>::type  \
instantiate_ptr_serialization( Serializable*, _Archive*, MyLib::adl_tag ); }}}

Теперь вам нужно сделать свой собственный макрос EXPORT, как в (/boost/serialization/export.hpp):

namespace MyLib {
namespace extra_detail {

template<class T>
struct guid_initializer
{
    void export_guid(mpl::false_) const {
        // generates the statically-initialized objects whose constructors
        // register the information allowing serialization of T objects
        // through pointers to their base classes.
        boost::archive::detail::
                instantiate_ptr_serialization((T*)0, 0,
                                              MyLib::adl_tag());
    }
    void export_guid(mpl::true_) const {
    }
    guid_initializer const & export_guid() const {
        BOOST_STATIC_WARNING(boost::is_polymorphic< T >::value);
        // note: exporting an abstract base class will have no effect
        // and cannot be used to instantitiate serialization code
        // (one might be using this in a DLL to instantiate code)
        //BOOST_STATIC_WARNING(! boost::serialization::is_abstract< T >::value);
        export_guid(boost::serialization::is_abstract< T >());
        return *this;
    }
};

template<typename T>
struct init_guid;

} // extra_detail
} // namespace MyLib



#define  MYLIB_CLASS_EXPORT_IMPLEMENT(T)                      \
    namespace MyLib  {                                        \
    namespace extra_detail {                                 \
    template<>                                               \
    struct init_guid< T > {                                  \
        static guid_initializer< T > const & g;              \
    };                                                       \
    guid_initializer< T > const & init_guid< T >::g =        \
        ::boost::serialization::singleton<                   \
            guid_initializer< T >                            \
        >::get_mutable_instance().export_guid();             \
    }}                                                     \
/**/

Хорошо, теперь вы можете определить свой собственный архив и зарегистрировать его с помощью:

MYLIB_SERIALIZATION_REGISTER_ARCHIVE(MyLib::xml_iarchive)

и в любое время, когда вы определяете сериализацию для своего класса, который имеет определенный синтаксис, доступный только для чтения MyLib:: custom_archive, вы можете использовать свою экспортную реализацию

BOOST_CLASS_EXPORT_KEY(MyClass) // in header
MYLIB_CLASS_EXPORT_IMPLEMENT(MyClass) // in cpp

(Обратите внимание, что экспорт ключа остается тем же самым форсированием...)

Это действительно здорово, потому что позволяет вам создавать свои собственные архивы и создавать архивы без ошибок. В любое время, когда вы хотите, чтобы сериализация boost просто использовала BOOST_CLASS_EXPORT, и в любое время, когда у вас есть класс для сериализации, используйте MYLIB_CLASS_EXPORT.

Надеюсь, что это может быть полезно!

Андреа Ригони Гарола