我正在尝试使用私有成员为嵌套类编写非侵入式boost ::序列化例程。 不幸的是,我没有说服g ++,序列化例程是内部类的朋友。 看来g ++需要序列化例程的前向声明,而这又需要一个嵌套类的前向声明,而这又不能用C ++来完成。 我错过了什么,或者这仅仅是不可能的? 铿锵++相比,不需要前向声明,并且与下面的代码没有问题。 以下代码说明了这个问题:
#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; }用-std=c++11和-lboost_serialization进行编译。 使用g ++进行编译时,抱怨即使存在朋友声明, member_也是私有的。 g ++是否拒绝内部类中的朋友声明?
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?
最满意答案
[dcl.meaning] / 1 :
当declarator-id被限定时,声明应引用预先定义的限定符所引用的类或名称空间的成员 (或者在名称空间的情况下,该名称空间的内联名字空间集的一个元素([ namespace.def]))或其专业化; [...]。
换句话说,具有限定名称的声明(包括朋友声明)必须引用先前声明的内容。 所以GCC在拒绝代码方面是正确的,但它应该在早期拒绝它,并且诊断相当混乱。 (请注意,如果被贿赂的对象是以前未声明的普通函数而不是模板,则它会在现场拒绝。)
此外,要求朋友访问类首先击败了非侵入式序列化的位置(这是为了让您序列化一个类而不更改其定义)。
[dcl.meaning]/1:
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).
更多推荐
发布评论