考虑以下程序
#include <iostream>
namespace N1
{
inline namespace N2
{
class A
{
public:
friend void f( const A & );
private:
int x = 10;
};
//void f( const A & );
}
void N2::f( const A &a ) { std::cout << a.x << '\n'; }
}
int main()
{
using namespace N1;
A a;
f( a );
} 根据C++ 17标准(10.3.1.2名称空间成员定义)
3如果非本地类中的朋友声明首先声明一个类、函数、类模板或函数template97,则朋友是最内部封闭名称空间的成员。朋友声明本身不会使名称对非限定查找(6.4.1)或限定查找(6.4.3)可见。
因此,朋友函数的名称在命名空间N2中是不可见的。因此,它也应该在命名空间N1中不可见。
但是,代码是在没有警告的情况下由clangHead10.0.0编译和执行的。
编译器gcc头10.0.0 20191发出警告
prog.cc:18:10: warning: 'void N1::N2::f(const N1::N2::A&)' has not been declared within 'N1::N2'
18 | void N2::f( const A &a ) { std::cout << a.x << '\n'; }
| ^~
prog.cc:10:25: note: only here as a 'friend'
10 | friend void f( const A & );
| ^但是运行程序,则输出正确的结果。
Visual C++ 2019也成功地编译了代码,没有警告,程序输出预期的结果。
这三个编译器是否有bug,因为名称f是不可见的,所以封闭名称空间中的朋友函数f的定义是不正确的?
发布于 2019-12-17 23:30:12
正如我在注释中提到的,f的函数体和参数并不是真正相关的,因为这个问题仅与N2::f的名称查找有关。删除它们之后,名称空间N2是否为inline也不重要。在这两种情况下,所有编译器的行为都是相同的。
GCC警告说,但是-pedantic-errors在N2::f的定义上犯了很大的错误。MSVC和Clang总是接受没有诊断的代码。
我认为您是对的,按照函数定义声明器中的N2::f的措辞,应该使用限定名查找规则来查找,如果在N2的作用域上没有f的中间声明,就不应该使用限定名来查找N2声明。
然而,有一个缺陷报告1477,它似乎有意图使这样一个命名空间外的定义格式良好。
在开放的中央工作组第1900期中,提出了这个问题,问题的描述也得出结论,标准的规范文本不允许定义。它还注意到,正如您所观察到的,存在实现差异。
对于Clang,有一个关于类似案例这里的bug报告。
https://stackoverflow.com/questions/59383156
复制相似问题