为何友元函数模板会呈现出友元关系的传递性?
C++23友元规则解析:为何该示例合法
要理解这个示例的合法性,需要结合两个关键的C++友元规则:
1. 类模板的互相友元声明
代码中的template <typename> friend class A;声明了核心规则:类模板A的所有实例之间互为友元。也就是说,对于任意类型T和U,A<T>是A<U>的友元,反之亦然。这意味着A<T>的作用域内可以直接访问A<U>的所有私有成员,就像访问自身成员一样。
2. 类内定义的友元函数的作用域规则
在类模板A<T>体内定义的友元函数模板test,遵循C++中类内定义友元函数的词法作用域规则:这类函数属于定义它的类的词法作用域,因此可以访问该类作用域内所有可访问的成员——包括该类友元的私有成员。
具体到你的示例:
- 当调用
test(ai, ac)时,实际实例化的是test(A<int>, A<char>),这个函数定义在A<int>的体内,因此处于A<int>的词法作用域中。 - 由于
A<int>和A<char>互为友元,A<int>的作用域内可以访问A<char>::i,而test作为A<int>作用域内的函数,自然也能访问A<char>::i。 - 同时,
test被A<int>声明为友元,因此可以直接访问A<int>::i。
这并没有违反友元的非传递性——test的访问权限并非来自“友元的友元”,而是来自它所处的A<int>词法作用域的原生访问能力。
补充:移除互相友元声明后的情况
当你移除template <typename> friend class A;后,A<int>不再是A<char>的友元,A<int>的作用域内无法访问A<char>::i,因此处于该作用域内的test也无法访问,编译器会报错。
而如果将test的定义移到类模板外部,此时test不再属于任何A<T>的词法作用域,它需要被A<int>和A<char>各自声明为友元才能访问两者的私有成员——由于每个A<T>实例都会将test函数模板声明为友元,因此此时代码可以正常编译。
内容的提问来源于stack exchange,提问作者bitmask
相关产品推荐
相关产品推荐

