嵌套类的类内好友是否可以访问外部类成员?

Does an in-class friend of a nested class have access to outer class members?

本文关键字:访问 外部 成员 是否 好友 嵌套      更新时间:2023-10-16

clang++、g++和MSVC在以下代码上存在分歧:

class A {
private:
enum class E { NO, YES };
class B {
private:
friend E f1() { return E::YES; }
// friend E f2();
};
};
// A::E f2() { return A::E::YES; }
int main() {}

clang++ 接受如图所示的代码。 g++和MSVC在f1抱怨A::E无法访问。 如果函数f2未被注释,则所有三个编译器都在其定义中抱怨A::E无法访问。

f1实际上有效吗?

我找到的相关标准件是:

[class.access.nest]:

嵌套类是一个成员,因此具有与任何其他成员相同的访问权限。

尽管仅凭这一点并不意味着嵌套类的好友拥有与嵌套类相同的所有权利。

[class.access.base]/5:

对成员的访问受命名成员的类的影响。此命名类是在其中查找和找到成员名称的类。在类N中命名时,可以在R点访问成员m

  • m作为N成员是公开的,或

  • m作为N的成员是私有的,而 R出现在类N的成员或朋友中,或者

  • m作为N成员受到保护,并且...,或

  • 存在一个基类BN,该基类可在 R 上
  • 访问,并且在类B中命名时m可在R上访问。

所以f2是无效的,因为那里A::E的命名类肯定是A的,不涉及基类,f2的定义不是A的成员或朋友,也不会"出现在"A的成员或朋友中。

f1,不合格E的命名类也A。 ([basic.lookup.unqual] 表示首先在类A::B中查找名称E,但在那里没有"找到",因此在类A中完成查找,并找到成员。 但我想最大的问题是,f1的定义是否"发生在"A的成员中? 如果是这样,该成员必须class A::B.

我认为gcc和msvc是对的。

从[class.friend]/1,强调我的:

的友元是一个函数或类,它被授予使用类中的私有和受保护成员名称的权限。类通过友元声明指定其友元(如果有)。这样的声明赋予朋友特殊的访问权限,但它们不会使被提名的朋友成为朋友阶层的成员。

当你有friend E f1()时,这给了f1使用B私有和受保护名称的权限,特别是。E不是B的私有或受保护的名称,它是B也可以访问的名称。


这在概念上类似于[class.friend]/10:

友谊既不是遗传的,也不是传递的。

由于这意味着规则是f1可以访问B的东西,而B可以访问A的东西,因此f1可以访问A的东西。