【发布时间】:2019-02-06 21:35:18
【问题描述】:
我最近发现友元声明作用域遵循extremely peculiar rules - 如果您有一个尚未声明的函数或类的friend 声明(定义),它会在紧接的命名空间中自动声明(定义) ,但是对非限定和限定查找是不可见的;但是,朋友 function 声明通过依赖于参数的查找仍然可见。
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
}
如果您查看标准(请参阅 linked answer),他们会竭尽全力启用这种古怪的行为,在具有复杂规则的合格/不合格查找中添加特定例外。最终结果在我看来非常令人困惑1,还有另一个角落案例要添加到实现中。作为任一
- 要求
friend声明引用现有名称、句号;或 - 允许他们像现在一样声明内容,但不更改普通名称查找(因此,这些名称变得可见,就像在封闭的命名空间中“正常”声明一样)
似乎更容易实现、指定,最重要的是,更容易理解,我想知道:他们为什么要为这个烂摊子烦恼?他们试图涵盖哪些用例?哪些更简单的规则(尤其是与现有行为最相似的第二条)违反了哪些规则?
-
例如,在这种特殊情况下
struct M { friend class N; }; N *foo; typedef int N;你会得到comically schizophrenic error messages
<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这样的东西,但是当您尝试提供冲突的声明时立即停止装傻。
【问题讨论】:
-
我不太确定您在这里寻找什么。就像...为什么只对 ADL 可见?
-
@Barry:我在问他们为什么要为这个烂摊子而烦恼,例如只是让它们对所有查找可见,没有创建那些“幻影”名称的奇怪规则。标准中少了几段,少了几千个神经元浪费在记住特殊情况,更简单的编译器实现。我的(可能是错误的)隐含假设是,如果他们达到这个长度来创建这些奇怪的半可见实体,那么他们的目标是一些特定的用例,但我想不出任何用例。
-
@MatteoItalia 我刚刚发现1996 (!) paper 有建议的措辞来禁止这样做。现在我只需要找到理由......
-
@NirFriedman 确实是相关的;阅读答案中链接的论文以获取血腥细节。
标签: c++ language-lawyer friend friend-function language-history