I have tried providing getters of class A
for my non-member serialize()
function` since accessing from members is private.
template
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. This
make_nvp
(because you can't use a.getRef()
as an XML element nameSadly, 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());
}
}
}
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
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
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