I am trying to write non-intrusive boost::serialization routines for a nested class with a private member. Unfortunately, I fail to convince g++ that the serialization routine is a friend of the inner class. It seems g++ requires a forward declaration of the serialization routine, which in turn would need a forward declaration of the nested class, which in turn cannot be done in C++. Am I missing something or is this just not possible? clang++ in contrast does not need a forward declaration and has no problems with the code below. The following code illustrates the problem:
#include <boost/archive/text_oarchive.hpp>
class Outer;
//class Outer::Inner; // Not valid C++
namespace boost
{
namespace serialization
{
template <class Archive>
void serialize(Archive &ar, Outer& outer, const unsigned int version);
//template <class Archive>
//void serialize(Archive &ar, Outer::Inner& inner, const unsigned int version); // Cannot be done since forward declaration of nested class not possible.
}
}
class Outer
{
class Inner
{
int member_{42};
template <class Archive>
friend void boost::serialization::serialize(Archive &ar, Outer::Inner &inner, const unsigned int version); // This does not work with gcc since the compiler seems to expect a forward declaration, which cannot be done (see above).
};
Inner inner_;
template <class Archive>
friend void boost::serialization::serialize(Archive &ar, Outer &outer, const unsigned int version);
template <class Archive>
friend void boost::serialization::serialize(Archive &ar, Inner &inner, const unsigned int version);
};
namespace boost
{
namespace serialization
{
template <class Archive>
void serialize(Archive &ar, Outer& outer, const unsigned int version)
{
ar & outer.inner_;
}
template <class Archive>
void serialize(Archive &ar, Outer::Inner& inner, const unsigned int version)
{
ar & inner.member_;
}
}
}
int main()
{
Outer outer;
boost::archive::text_oarchive(std::cout) << outer;
}
To be compiled with -std=c++11
and -lboost_serialization
. Compilation with g++ complains that member_
is private even though a friend declaration is present. Is g++ right in refusing the friend declaration in the inner class?
When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers (or, in the case of a namespace, of an element of the inline namespace set of that namespace ([namespace.def])) or to a specialization thereof; [...].
In other words, a declaration (including a friend declaration) with a qualified name must refer to something previously declared. So GCC is sort of correct in rejecting the code, but it should have rejected it earlier, and the diagnostic is rather confusing. (Note that it will reject it on the spot if the thing being friended is a previously-undeclared plain function and not a template.)
Also, requiring friend access sort of defeats the point of non-intrusive serialization in the first place (which is to allow you to serialize a class without changing its definition).