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 代码依赖于编译器静态地将 any type_code 和正确的类型放在占位符中。你肯定不能在 C++ 的反序列化中做到这一点,因为你从反序列化中获得的类型在编译时是未知的(正如新形成的 所要求的那样boost::any)。

最好的解决方案是为您要序列化的元素的确切类型构建某种专门的 any 类型。然后,您可以对要反序列化的元素的实际类型有特殊情况,但请注意,每个元素类型的序列化/反序列化都必须在物理上编写为静态 C++ 代码。

PD。其他一些人建议使用boost::variant作为这种特殊类型的表示,其中包含您要序列化的确切类型。不过,您需要一种方法来识别反序列化的确切类型(可能为变体中的类型分配标识符)。

于 2010-09-08T22:22:34.033 回答
1

无需创建新类。尝试使用 xany https://sourceforge.net/projects/extendableany/?source=directory xany 类允许向任何现有功能添加新方法。顺便说一句,文档中有一个示例可以完全满足您的要求。

于 2012-12-17T11:54:28.047 回答
1

假设您必须使用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并使用key 下的地址填充地图&typeid(T)。您可以专门化该类any_serializer并使用一些(丑陋的)宏来填充地图。

更困难的当然是反序列化。好久没看boost::lexical_cast,或许能帮上忙。恐怕这完全取决于问题。但是,您只需要一个函数,它接受 astring并返回一个any。您可能还想在输出字符串前添加自定义类型标识符。

于 2010-09-08T22:30:11.100 回答