12

私が理解している限り、プレースホルダーのシリアル化(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

4 に答える 4

6

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;
}
于 2012-03-03T12:14:20.607 に答える
5

少なくとも任意のタイプでは、まったく不可能です。トリッキーなコード(anyに含まれる要素のサイズを見つけるなど)を使用してシリアル化できる場合もありますが、anyコードは、コンパイラーに依存して、anytype_codeと適切なをプレースホルダー内に静的に配置します。C ++の逆シリアル化では、これを行うことはできません。逆シリアル化から取得するタイプは、コンパイル時に(新しく形成されたもので必要とされるようにboost::any)不明であるためです。

最善の解決策は、シリアル化する要素の正確なタイプに合わせて、ある種の特殊なタイプを構築することです。次に、逆シリアル化される要素の実際のタイプに特別な場合がありますが、各要素タイプのシリアル化/逆シリアル化は、静的C++コードとして物理的に記述される必要があることに注意してください。

PD。boost::variant他の何人かは、シリアル化しようとしている正確な型を保持するこの特殊な型の表現として使用することを提案しました。ただし、逆シリアル化で正確なタイプを識別する方法が必要です(バリアントのタイプに識別子を割り当てる場合があります)。

于 2010-09-08T22:22:34.033 に答える
1

boost::anyを使用する必要があり、に切り替えることができないと仮定するとvariantmap<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しばらく見ていませんでした、おそらくそれはいくつかの助けを提供することができます。これは完全に問題に依存しているのではないかと思います。ただし、必要な関数は1つだけです。この関数は、を取り、string1つを返しますany。また、出力文字列の前にカスタムタイプ識別子を追加することもできます。

于 2010-09-08T22:30:11.100 に答える
1

新しいクラスを作成する必要はありません。xanyを使用してみてくださいhttps://sourceforge.net/projects/extendableany/?source=directoryxany クラスを使用すると、既存の機能に新しいメソッドを追加できます。ちなみに、ドキュメントにはあなたが望むことを正確に行う例があります。

于 2012-12-17T11:54:28.047 に答える