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

  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