Члены личные данные для неинтрузивной буст сериализация в C++


Я попытался предоставить геттеры класса A для моей функции, не являющейся членом serialize(), так как доступ из членов является частным.

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);
К сожалению, исполнение продолжает говорить мне uncaught exception of type boost::archive::xml_archive_exception - Invalid XML tag name, Когда я пытаюсь использовать геттеры GetRef() или GetId().
Он хорошо работает, если я обращаюсь непосредственно к m_id, когда он открыт. Есть ли какие-нибудь хорошие способы сделать это ?
2 6

2 ответа:

  1. Вы можете использовать старых добрых друзей:

    Жить На Колиру

    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

    К сожалению, наличие ссылочного геттера нарушает инкапсуляцию ужасным образом. Я лично предпочел бы иметь m_id публику в первом вместо этого-место.

    Жить На Колиру

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

    Смотрите жить на Колиру также

Просто для дополнительной информации: чтобы получить первое решение от sehe working:

Вам нужно прямое склонение метода friends следующим образом:

// 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();
};
Мне потребовалось некоторое время, чтобы заставить его работать.

Ура