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

后端 未结 3 541
余生分开走
余生分开走 2020-12-06 03:01

I have tried providing getters of class A for my non-member serialize() function` since accessing from members is private.

template         


        
相关标签:
3条回答
  • 2020-12-06 03:33
    1. 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);
          }
      }
      }
      

    2. You can use the getRef() approach. This

      • requires no friends (less intrusive)
      • requires make_nvp (because you can't use a.getRef() as an XML element name

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

      Bonus points:

    3. You can use a 'pimpl' style struct. You can forward declare a struct inside A<>:

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

      That's less intrusive than the getRef() approach which simply breaks encapsulation all the way. Now, you can hide the 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 this can be done in a separate header and doesn't influence 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);
          }
      };
      

      See it Live On Coliru as well

    0 讨论(0)
  • 2020-12-06 03:40

    Just for additional info: In order to get the first solution from sehe working:

    You need a forward decleration of the friends method like this:

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

    Took me a while to get it working.

    Cheers

    0 讨论(0)
  • 2020-12-06 03:45

    Supplementary Information to sehe's first solution:

    The solution requires two-phase lookup and or argument dependent lookup. Unfortunately, MSVC does not yet support this to its full extent.

    Compiling this in VS Community 2019 16.1.6 with boost 1.70 results in an obscure error:

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

    Even though conformance mode is enabled through the /permissive- flag and the latest language standard /std::c++latest is selected, as described in this MSVC Blog Post.

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

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

    Even more interestingly frustratingly:

    if class A is not a templated class, then it doesn't work either way, same error as above... Example code: http://coliru.stacked-crooked.com/a/ecfbb39d5975d753

    0 讨论(0)
提交回复
热议问题