VS2015和clang编译这段代码,但g++却拒绝。哪一个是正确的?

9

VS2015clang可以编译这段代码,但是g++无法通过编译

namespace A {
   struct B {
      friend void f();
   };
}
void A::f() {}

int main(){
}

我认为g++是正确的,因为7.3.1.2/3中的注释如下:
如果非局部类中的友元声明首先声明了一个类、函数、类模板或函数模板,那么友元就是最内层封闭命名空间的成员。友元声明本身不会使名称对未限定查找([basic.lookup.unqual])或限定查找([basic.lookup.qual])可见。【注意:如果在命名空间范围内提供了相应的匹配声明(在类定义授予友谊之前或之后),则友元的名称将在其命名空间中可见。-注】如果调用友元函数或函数模板,则可以通过考虑与函数参数类型相关联的命名空间和类的函数进行名称查找([basic.lookup.argdep])来找到它的名称。如果友元声明中的名称既不是限定的也不是模板ID,并且声明是函数或扩展类型说明符,则用于确定实体是否已经声明的查找不应考虑最内层封闭命名空间以外的任何作用域。【注意:其他形式的友元声明不能声明最内层封闭命名空间的新成员,因此遵循通常的查找规则。-注】

1
相关:http://stackoverflow.com/questions/24600050/clang-a-friend-function-defined-within-a-class - NathanOliver
1个回答

6

您引用的部分比您强调的注释更具有明确性:

友元声明本身并不使名称对于未限定查找([basic.lookup.unqual])或限定查找([basic.lookup.qual])可见。

您的定义依靠限定查找来查找已在命名空间中声明的函数。但是该名称未对限定查找可见。此代码应被拒绝。

下面是相关规则,它在第8.3节 [dcl.meaning] 中找到:

当声明符号标识已限定时,声明应引用类或命名空间的先前声明的成员,该限定符所指的(或者,在命名空间的情况下,该命名空间的内联命名空间集的元素),或其专业化;该成员不仅仅是由声明符号ID的嵌套名称指定的类或命名空间的作用域中使用声明引入的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接