template<typename T> class List { protected: class a { int x; int y; private: friend class b; // <------------ Why this is not an error? }; template <typename U > class b { //If that is not a error this should be an error int z; U y; }; public: List() { a* ptr = (a *)new unsigned char[sizeof(a)]; } }; int main() { List<int> mylist; }
请仔细阅读此链接,我的问题在代码中作为评论.
我想让另一堂课成为我班上的朋友.但在结交朋友时,这个班级并不知道.什么是允许它的C规则.
后来我以这样的方式定义该类,它与朋友声明不兼容.为什么不抛出错误.
谢谢
解决方法
class List { public: class a { typedef int type; friend class b; // that's fine! }; template <typename U > class b; }; class b { List::a::type an_int; // allowed to access private member };
标准说明在7.3.1.2/3
If a friend declaration in a non-local class first declares a class or function83) the friend class or function is a member of the innermost enclosing namespace.
什么时候是“第一次宣布的课程”?它也说那里
When looking for a prior declaration of a class or a function declared as a friend,and when the name of the friend class or function is neither a qualified name nor a template-id,scopes outside the innermost enclosing namespace scope are not considered.
“class b”的查找从7.1.5.3/2委派给3.4.4,后者又委托3.4 / 7的非限定名称查找.现在的所有问题是模板名称“b”是否在朋友声明类a中可见.如果不是,则找不到名称,并且friend声明将引用全局范围内的新声明的类. 3.3.6 / 1关于它的范围说
The potential scope of a name declared in a class consists not only of the declarative region following
the name’s declarator,but also of all function bodies,default arguments,and constructor ctor-
initializers in that class (including such things in nested classes).
忽略一些会使这个措辞不适用的迂腐点(这是一个缺陷但在该段的C 0x版本中修复,这也使这更容易阅读),这个列表不包括朋友声明作为一个区域模板名称可见的位置.
但是,该朋友是在类模板的成员类中声明的.实例化成员类时,将应用不同的查找 – 查找在类模板中声明的朋友名称!标准说
Friend classes or functions can be declared within a class template. When a template is instantiated,the
names of its friends are treated as if the specialization had been explicitly declared at its point of instantiation.
因此以下代码无效:
template<typename T> class List { public: class a { typedef int type; friend class b; // that's fine! }; template <typename U > class b; }; // POI List<int>::a x;
当这导致List< int> :: a被隐式实例化时,名称a被查找为“// POI”,好像会声明一个显式的特化.在这种情况下,模板List :: b已经被声明,并且此查找将命中它并发出错误,因为它是模板而不是非模板类.