Члены личные данные для неинтрузивной буст сериализация в 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 ответа:
Вы можете использовать старых добрых друзей:
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); } } }
Вы можете использовать подход
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()); } } }
Бонусные очки:
Вы можете использовать структуру стиля "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(); };
Ура