Get private data for non-intrusive forcing C ++ serialization

I tried to provide class A getters for my non-member serialize() function, since access to members from them is private.

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

Unfortunately, execution keeps telling me uncaught exception of type boost::archive::xml_archive_exception - Invalid XML tag name when I try to use either GetRef() or GetId() .
It works well if I access m_id directly when it is public.

Are there any good ways to do this?

+8
source share
3 answers
  • You can use good old fashioned friends:

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

  • You can use the getRef() approach. it

    • no friends required (less intrusive)
    • requires make_nvp (because you cannot use a.getRef() as the name of an XML element

    Unfortunately, dropping the cross-getter encapsulation in a horrible way. Instead, I would rather have m_id public.

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

    Bonus points:

  • You can use the pimpl style structure. You can forward the structure declaration inside A<> :

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

    This is less intrusive than the getRef() approach, which simply destroys encapsulation completely. Now you can hide private access inside this 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); } } } 

    Of course, you still need to implement it, but you can do this in a separate header and not affect the class A <(or any of its specializations) at all:

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

    Watch Live On Coliru as well

+13
source

For additional information only: To get the first solution from sehe :

You need a forward declaration of the friends method as follows:

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

The time has come to make it work.

Greetings

+1
source

Additional information for finding the first solution:

The solution requires a two-phase search or an argument-dependent search. Unfortunately, MSVC does not yet fully support this.

Compiling this in VS Community 2019 16.1.6 with add-in 1.70 leads to an unclear error:

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

Despite the fact that compliance mode is activated using the / permissive- flag and the latest language standard / std :: C ++ is selected, as described in this MSVC blog post .

Adding a typename qualifier to a friend declaration solves the problem:

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

Even more interesting is the disappointment:

if class A is not a template class, then it does not work in any case, the same error as above ... Code example: http://coliru.stacked-crooked.com/a/ecfbb39d5975d753

0
source

All Articles