成员函数Outer::f()不是类Outer::Inner的友类.为什么

The member function Outer::f() is not a friend of class Outer::Inner. Why?

本文关键字:Outer Inner 为什么 函数 成员      更新时间:2023-10-16

根据clang, gcc和vs2013,函数Outer::f不是 Outer::Inner类的友元。

struct Outer {
    void f() {}
    class Inner {
        friend void f();
        static const int i = 0;
    };
};
void f() { int i = Outer::Inner::i; }

从[名称空间。我希望函数Outer::fOuter::Inner的朋友,而不是::f,因为朋友声明不是第一个在其包含名称f的命名空间。

[namespace,memdef]/3(我的重点):

在命名空间中首先声明的每个名称都是该命名空间的成员名称空间。如果非局部类中的友元声明首先声明一个类、函数、类模板或函数模板97的友元是最内层的成员包含名称空间。朋友声明本身并不能使非限定查找(3.4.1)或限定查找可见的名称(3.4.3)。[注意:好友的名字将在其如果在命名空间范围内提供了匹配声明,则使用(在授予友谊的类定义之前或之后)。- - - - - -如果一个友元函数或函数模板被调用,它将被调用名称可以通过考虑来自的函数的名称查找找到与函数类型相关联的命名空间和类参数(3.4.2)。如果友元声明中的名称两者都不是限定不是模板id,声明是一个函数或详细的类型说明符,查找以确定实体是否已事先声明的不得考虑任何范围以外的最内层封闭命名空间。

你引用的标准的第一部分说(强调我的):

在命名空间中首先声明的每个名称都是该命名空间的成员。如果非局部类中的友元声明首先声明了一个类或函数,则友元类或函数是最内层封闭命名空间的成员。

你假设一个类和一个命名空间是一样的,这是不正确的。

namespace Outer {
    void f();
    class Inner {
        friend void f();
        static const int i = 0;
    };
}
void Outer::f() { int i = Outer::Inner::i; }

应该工作。要使用类成员函数作为友元,必须使用:

struct Outer {
    void f();
    class Inner {
        friend void Outer::f();
        static const int i = 0;
    };
};
void Outer::f() { int i = Outer::Inner::i; }

根据[namspace .memdef]:

如果friend声明中的名称都不是如果不是模板id,并且声明是函数或详细的类型说明符,则查找确定实体之前是否声明过,不应考虑最内层之外的任何作用域包含名称空间。

"outside"是什么意思?它可能意味着(1)外部的(例如,允许最内层封闭名称空间内的所有作用域,但不允许其他作用域),也可能意味着(2)排除的(例如,只考虑最内层封闭名称空间)。措辞可能含糊不清。然而,考虑这个由OP的原始问题和OP的评论合并而成的例子:

struct Outer {
    void f() { }
    class C { void foo(); };
    class Inner {
        friend class C;
        friend void f();
        static const int i = 0;
    };
};
void f() { (void)Outer::Inner::i; }               // compiles on GCC,Clang
void Outer::C::foo() { (void)Outer::Inner::i; }   // compiles on GCC,Clang
int main() { }

根据措辞(1),Outer::fOuter::C应该是Inner的友元。根据措辞(2),::f::C应该是朋友。一种或另一种解释可能是有意义的,然而GCC和Clang最终都以::fOuter::C作为朋友,这显然没有任何意义。我已经提交了GCC Bug 66836和Clang Bug 24088。所以要么两个编译器都在这个或那个方向上有错误,要么是标准的某些部分解释了这个逻辑,我肯定没有注意到。我不反对后者。