获取用于非侵入性提升序列化C++的私有数据成员

Get private data members for non intrusive boost serialization C++

本文关键字:C++ 序列化 数据成员 升序 用于 获取      更新时间:2023-10-16

我已经尝试为我的非成员serialize()函数提供类A的getter,因为从成员的访问是私有的。

template<typename T>
class A
{
public:
  A(const T& id) : m_id(id) {}
  T& getRef() { return m_id; } // not giving good results
  T  getId()  { return m_id; } // not giving good results
  const T& getRef() const { return m_id; } // not giving good results
private: // I would like to keep it private
  T m_id;
}
namespace boost { namespace serialization {
template<class Archive,typename T>
void serialize(Archive &ar, A &a, const unsigned int version)
{
    // ar &BOOST_SERIALIZATION_NVP(a.m_id); // I would like to avoid that it works if m_id is public
    ar &BOOST_SERIALIZATION_NVP(a.GetRef()); // I want this !
}
}}
// and later I use
std::ofstream ofs("test.xml");
boost::archive::xml_oarchive oa(ofs);
A<int> a(42);
oa << BOOST_SERIALIZATION_NVP(a);

不幸的是,当我尝试使用getter GetRef()GetId()时,执行一直告诉我uncaught exception of type boost::archive::xml_archive_exception - Invalid XML tag name
如果我在m_id公开时直接访问它,效果会很好。

有什么好方法吗?

  1. 你可以使用好的老式朋友:

    在Coliru上直播

    template <typename T>
    class A {
      public:
        A(const T &id) : m_id(id) {}
      private:
        template <typename Ar, typename U> friend void boost::serialization::serialize(Ar&,A<U>&,const unsigned);
        T m_id;
    };
    namespace boost {
    namespace serialization {
        template <class Archive, typename T>
        void serialize(Archive &ar, A<T> &a, const unsigned int)
        {
            ar & BOOST_SERIALIZATION_NVP(a.m_id);
        }
    }
    }
    

  2. 您可以使用getRef()方法。这个

    • 不需要朋友(侵扰性较小(
    • 需要make_nvp(因为不能将a.getRef()用作XML元素名称

    可悲的是,引用getter以一种可怕的方式破坏了封装。我个人更愿意首先公开m_id

    在Coliru上直播

    template <typename T>
    class A {
    public:
        A(const T &id) : m_id(id) {}
        T& getRef()             { return m_id; } 
        T const& getRef() const { return m_id; } 
    private:
        T m_id;
    };
    namespace boost {
    namespace serialization {
        template <class Archive, typename T>
        void serialize(Archive &ar, A<T> &a, const unsigned int)
        {
            ar & boost::serialization::make_nvp("m_id", a.getRef());
        }
    }
    }
    

    奖励积分:

  3. 您可以使用"pimpl"样式的结构。您可以在A<>:中转发声明一个结构

    template <typename T>
    class A {
    public:
        struct access;
        A(const T &id) : m_id(id) {}
    private:
        T m_id;
    };
    

    这比getRef()方法侵入性更小,后者只是一路破坏封装。现在,您可以将私有访问隐藏在这个类中:

    namespace boost {
    namespace serialization {
        template <class Archive, typename T>
        void serialize(Archive &ar, A<T> &a, const unsigned int version)
        {
            A<T>::access::serialize(ar, a, version);
        }
    }
    }
    

    当然,您仍然需要实现它,但这可以在单独的头中完成,并且不会影响类a<>(或其任何专业(:

    template <typename T>
    struct A<T>::access {
        template <class Archive>
        static void serialize(Archive &ar, A<T> &a, const unsigned int) {
            ar & BOOST_SERIALIZATION_NVP(a.m_id);
        }
    };
    

    查看Coliru直播以及

仅用于其他信息:为了从获得第一个解决方案,正在工作:

您需要一个朋友的前向分离方法,如下所示:

// Boost
#include <boost/serialization/access.hpp>
class ClassB;
namespace boost{
namespace serialization {
    template <typename Ar> void serialize(Ar&,ClassB&,const unsigned);
}
}
class ClassB: public ClassA{
private:
    template <typename Ar> friend void boost::serialization::serialize(Ar&,ClassA&,const unsigned);
public:
    ClassA();
    virtual ~ClassA();
};

我花了一段时间才开始工作。

干杯

第一个解决方案的补充信息:

该解决方案需要两阶段查找和/或依赖于参数的查找。不幸的是,微软风投公司还没有完全支持这一点。

在VS Community 2019 16.1.6和boost 1.70中编译此代码会导致一个模糊错误:

Error   C2063    'boost::serialization::serialize': not a function

尽管一致性模式是通过/permission-标志启用的,并且选择了最新的语言标准/std::c++latest,如本MSVC博客文章所述。

在友元声明中添加typename限定符可以解决问题:

template <typename Ar, typename U> friend void boost::serialization::serialize(typename Ar&, A<U>&, const unsigned);

更有趣的是令人沮丧的是:

若类A不是一个模板化的类,那个么它无论如何都不起作用,和上面的错误相同。。。示例代码:http://coliru.stacked-crooked.com/a/ecfbb39d5975d753