根据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; }
从[namespace.memdef] / 3我希望函数Outer::f
成为Outer::Inner
的朋友,而不是::f
,因为朋友声明不是第一个在其名称空间中,包含名称f
。
[namespace,memdef] / 3(重点是我的):
首先在名称空间中声明的每个名称都是其中的一员 命名空间。如果非本地班级中的朋友声明第一 声明一个类,函数,类模板或函数 模板 97 朋友是最里面的成员 封闭命名空间。朋友声明本身并没有 非限定查找(3.4.1)或限定查找可见的名称 (3.4.3)。 [注意:朋友的名字将在其中显示 如果在命名空间范围内提供匹配的声明,则为namespace (在授予友谊的班级定义之前或之后)。 - 结束注释]如果调用了友元函数或函数模板,则为其 可以通过名称查找找到名称来查找函数 与函数类型相关联的名称空间和类 参数(3.4.2)。如果朋友声明中的名字都不是 限定也不是模板ID,声明是函数或 elaborated-type-specifier,查找是否确定实体 先前已宣布不得考虑任何范围以外的 最里面的封闭命名空间。
答案 0 :(得分:9)
您引用的标准的第一部分(强调我的):
首先在名称空间中声明的每个名称都是该名称空间的成员。如果非本地类中的友元声明首先声明一个类或函数,那么友元类或函数是最内层封闭命名空间的成员。
您假设某个类与命名空间相同,这是不正确的。
IDAT
应该有效。要将类成员函数用作朋友,您必须使用:
IEND
答案 1 :(得分:2)
根据[namespace.memdef]:
如果
friend
声明中的名称都不是 限定也不是模板ID,声明是一个函数或一个精心设计的类型说明符,用于确定实体是否先前已声明的查找不应考虑任何范围外部最内部 封闭命名空间。
“外面”是什么意思?它可能意味着(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::f
和Outer::C
应该是Inner
的朋友。根据措辞(2),::f
和::C
应该是朋友。一个或另一个解释可能有意义,但GCC和Clang最终都以::f
和Outer::C
作为朋友,这显然没有任何意义。我已提交GCC Bug 66836和Clang Bug 24088。所以要么两个编译器在一个方向或另一个方向都是错误的,或者标准的某些部分解释了这个逻辑肯定会让我失望。我不打赌后者。