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

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

我已经尝试为我的非成员 serialize() 函数提供 class 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);

不幸的是,当我尝试使用 GetRef()GetId().
时,执行一直告诉我 uncaught exception of type boost::archive::xml_archive_exception - Invalid XML tag name 如果我在 public.

时直接访问 m_id,效果会很好

有什么好的方法吗?

  1. 你可以用的好 old-fashioned 朋友:

    Live On 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元素名

    Sadly, having the reference getter break encapsulation in a horrific way. I'd personally prefer to have m_id public in the first place, instead.

    Live On 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() 方法更具侵入性。现在,您可以在 class:

    中隐藏私有访问权限
    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);
        }
    }
    }
    

    当然你仍然需要实现它,但这可以在单独的 header 中完成并且根本不会影响 class 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);
        }
    };
    

    也看看Live On Coliru

仅供补充信息:为了从 sehe 获得第一个解决方案:

你需要一个前向减速的朋友方法如下:

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

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

干杯

sehe第一个解的补充信息:

该解决方案需要 two-phase 查找和/或参数依赖查找。不幸的是,MSVC 还没有完全支持它。

在带有 boost 1.70 的 VS Community 2019 16.1.6 中编译它会导致一个模糊的错误:

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

尽管通过 /permissive- 标志启用了一致性模式并且选择了最新的语言标准 /std::c++latest,如 this MSVC Blog Post 中所述。

在友元声明中添加类型名限定符解决问题:

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

有趣令人沮丧:

如果class A 不是模板化的class,那么无论哪种方式都不起作用,与上述相同的错误... 示例代码:http://coliru.stacked-crooked.com/a/ecfbb39d5975d753