我最近发现朋友声明范围如下 非常特殊的规则 - 如果你有 friend
对于尚未声明的函数或类的声明(定义),它在直接封闭的命名空间中自动声明(定义), 但 它对于不合格和合格的查找是不可见的;不过,朋友 功能 声明通过依赖于参数的查找保持可见。
struct M {
friend void foo();
friend void bar(M);
};
void baz() {
foo(); // error, unqualified lookup cannot find it
::foo(); // error, qualified lookup cannot find it
bar(M()); // ok, thanks to ADL magic
}
如果你看一下标准(参见 相关答案),他们花了很大的力气来实现这种古怪的行为,在复杂规则的合格/非合格查找中添加了一个特定的异常。最终的结果让我非常困惑1,还有另一个案例要添加到实现中。作为
- 要求
friend
声明引用现有名称,期间;要么 - 允许他们像现在一样声明东西,但不改变普通的名字查找(因此,这样的名称变得可见,好像在封闭的命名空间中声明为“正常”)
似乎更容易实现,指定,最重要的是,理解,我想知道:为什么他们为这个烂摊子烦恼?他们试图覆盖哪些用例?在任何这些更简单的规则下(特别是第二个与现有行为最相似的规则)会破坏什么?
例如,在这种特殊情况下
struct M { friend class N; }; N *foo; typedef int N;
你得到 可笑的精神分裂症错误信息
<source>:4:1: error: 'N' does not name a type N *foo; ^ <source>:5:13: error: conflicting declaration 'typedef int N' typedef int N; ^ <source>:2:17: note: previous declaration as 'class N' friend class N; ^
编译器首先声称没有这样的东西
N
,但是当你试图提供相互矛盾的声明时,立即停止玩愚蠢。