10

注:
Boost のアーカイブ スキームは、対称的な入力と出力のアーカイブ クラスに基づいています。両方についていつも書くのは面倒なので、私はと の両方を?archive意味します。oarchiveiarchive

概要:
カスタム アーカイブの基本クラスを から に変更した後、コンパイラが他のクラスのメソッドをインスタンス化しているときbinary_?archive_impltext_?archive_impl、カスタム アーカイブ クラスが「見つからない」ようになりましたserialize(...)

背景:
私のアプリケーションは、 のサブクラスを使用してファイルの読み取りとディスクへの書き込みに成功していましたbinary_?archive_impl(ドキュメントやコードのコメントでは、 から派生するよりもこれを推奨していますbinary_?archive)。バイナリ ファイル形式からテキスト形式に切り替える必要があったため、カスタム アーカイブの基本クラスをtext_?archive_impl. その時、すべてが爆発しました。

問題:
私のカスタム アーカイブ クラスは、Boost 基本クラスには存在しないいくつかの追加メソッドを含む機能を追加します。これらのメソッドはserialize(...)、私のクラスの多くのメソッドで呼び出され、正常に機能していました。基本クラスを から に変更した後binary_?archive_impl、カスタム メソッドが に存在しないtext_?archive_implというコンパイル エラーがあちこちで発生しました。それは明らかです (!!!) が、それらは私のカスタムアーカイブに存在し、 Boost のバイナリ ベース クラスを使用していたときは問題なく動作していました。どうしたんだ?text_?archive

私が見つけたものと、私の一時的な - しかし望ましくない - 解決策:
髪を引き裂いて約 1 日ぐるぐる回った後、これが私が見つけたものです...

1) 少し前 (Boost 1.34 だと思います)、ファイル "binary_?archive.hpp" は "binary_?archive_impl.hpp" と "binary_?archive.hpp" に分割されました (後者は前者を #include します)。これは、「text_?archive.hpp」には行われませんでした。(結果として、アプリケーションの #include 行を「binary_?archive_impl.hpp」から単に「text_?archive.hpp」に変更しました。)

2) "text_?archive.hpp" を 2 つの部分に分割し、"..._impl.hpp" ヘッダーのみを #include すると、すべてが機能します。(しかし、Boost のインストールを変更したくありません!)

3)これらのヘッダーを詳しく見て、少しいじってみると、元の変更されていないヘッダーを使用して行をコメントアウトすると、

BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::archive::text_oarchive)

(および同様にtext_iarchive)、すべてが再び正常に機能します。(ちなみに、自分のアーカイブ コードに、カスタム アーカイブを「登録」するための同様の行があります。)

謎と私のジレンマ:
A) なぜこれらの線の存在が作品を汚すのか? ...そして、それらを削除すると機能するのはなぜですか? ...そして、そうすることで (知らず知らずのうちに) 何を壊してしまったのでしょうか?

B) 昔、「text_?archive.hpp」ファイルが「binary_?archive.hpp」ファイルと一緒に分割されなかったのはなぜですか? (ライブラリが壊れていませんか? 修正する必要がありますか?)

C) Boost のインストールを変更せずに、アプリケーション コードでこれを解決する方法はありますか?

PS 私は Boost 1.48 と Visual Studio 2010 (64 ビット)
PPS を使用しています 上記のすべてが等しく適用されると思いますtext_w?archive

4

3 に答える 3

1

これは答えではなくヒントなので、コメントにしたいと思います。ただし、質問にコメントを追加するオプションが表示されません (また、編集ボタンでやりたいことを実行できるとは思いません)。

私の 1.49.0 インストールでは、対応するテキスト型の実装ファイルも表示されます。これらは、impl ディレクトリに .ipp 形式で格納されています。タイムスタンプは、それらが最近変更されていないことを示唆しているため、1.48 と同じはずです。問題を解明するのに役立つかもしれません。

Dave Abrahams 氏によると、.ipp ファイルは実装を隠すことになっています。彼らが異なるスタイルを選んだ理由はわかりません。

----------+ 1 stackoverflow なし 2936 2009 年 12 月 5 日 ./binary_iarchive_impl.hpp

----------+ 1 stackoverflow なし 2966 2009 年 12 月 5 日 ./binary_oarchive_impl.hpp

----------+ 1 stackoverflow なし 1392 2007 年 11 月 25 日 ./detail/basic_archive_impl.hpp

----------+ 1 stackoverflow なし 3458 2009 年 5 月 20 日 ./impl/text_iarchive_impl.ipp

----------+ 1 stackoverflow なし 3290 2005 年 7 月 2 日 ./impl/text_oarchive_impl.ipp

----------+ 1 stackoverflow なし 3020 2008 年 6 月 26 日 ./impl/text_wiarchive_impl.ipp

----------+ 1 stackoverflow なし 2244 2005 年 7 月 2 日 ./impl/text_woarchive_impl.ipp

于 2012-05-28T19:29:26.133 に答える
1

せいぜい、ブーストシリアル化のバグだと言えます。ここで見ていきます

A)
1. BOOST_SERIALIZATION_REGISTER_ARCHIVE を新しいアーカイブに追加しても、デフォルトのテキスト アーカイブが既に登録されているため、機能しません。登録のみが許可されているようです。
2.カスタムクラスのみが登録されているため、それらを削除すると機能します。
3. それらを削除すると、デフォルトのテキスト アーカイブを使用できなくなります。クラスは登録されます。

B )
「text_?archive.hpp」ファイルは「binary_?archive.hpp」ファイルのように分割されるべきだったと確信しています。パッチブースト誰か?

C )
最善の解決策は、ファイルを分割するパッチをブーストに送信することです。一時的な解決策としては、パッチがブーストされるまで、パッチを適用したファイルをプロジェクトにローカルに配置するのがおそらく最善の方法です。

于 2012-06-29T05:33:10.097 に答える
0

ライブラリのカスタムアーカイブを実装するために、同じ問題が発生しました。解決策の可能性のあるトリックを見つけました。うまく機能しているようですので、共有します。

シリアル化構文が変更されたクラスをブースト アーカイブにエクスポートする方法はないため、これをまったく回避する必要があります。

ブースト アーカイブ登録は、適切にオーバーロードされた関数を使用して、ポインターのシリアル化型のインスタンスを作成します ( 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 は、boost が実装内を参照できるようにするために使用できるクールなオーバーロード機能を追加することに注意してください。新しい登録宣言を次のように入力するだけです。

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

ここで、( /boost/serialization/export.hpp )のように独自の EXPORT マクロを作成する必要があります。

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

(キーのエクスポートはブーストと同じままであることに注意してください ... )

これは、カスタム アーカイブとブースト アーカイブをエラーなしで共存させることができるため、非常に優れています。

これが役に立つことを願っています!

アンドレア・リゴーニ・ガローラ

于 2013-08-24T13:11:09.843 に答える