Mat*_*lia 11 c++ friend language-history friend-function language-lawyer
我最近发现朋友声明范围遵循极其特殊的规则 - 如果你有一个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
}
Run Code Online (Sandbox Code Playgroud)
如果你看一下标准(参见链接的答案),他们就会付出很大的代价来启用这种古怪的行为,在复杂规则的限定/非限定查找中添加一个特定的例外.最终的结果让我感到非常困惑1,还有另一个案例要添加到实现中.作为
friend
声明引用现有名称,期限; 要么似乎更容易实现,指定,最重要的是,理解,我想知道:为什么他们为这个烂摊子烦恼?他们试图覆盖哪些用例?在任何这些更简单的规则下(特别是第二个与现有行为最相似的规则)会破坏什么?
例如,在这种特殊情况下
struct M {
friend class N;
};
N *foo;
typedef int N;
Run Code Online (Sandbox Code Playgroud)
你得到可笑的精神分裂症错误信息
<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;
^
Run Code Online (Sandbox Code Playgroud)
编译器首先声称没有这样的东西N
,但是当你试图提供冲突的声明时立即停止玩愚蠢.
Ded*_*tor 13
那么,为了回答这个问题,你必须看看C++的另一个主要特性:模板.
考虑一个这样的模板:
template <class T>
struct magic {
friend bool do_magic(T*) { return true; }
};
Run Code Online (Sandbox Code Playgroud)
在这样的代码中使用:
bool do_magic(void*) { return false; }
int main() {
return do_magic((int*)0);
}
Run Code Online (Sandbox Code Playgroud)
退出代码是0
或者1
?
嗯,这取决于是否magic
曾在int
任何可观察的地方实例化.
至少它会,如果friend
- 仅在内联声明的函数将由普通的查找规则找到.
而且你不能通过注入所有可能的东西来打破这个难题,因为模板可以是专用的.
这种情况曾经是一段时间,但被视为"太神奇","太不明确".
名称注入还存在其他问题,因为它没有像希望的那样明确定义.有关详细信息,请参阅N0777:模板中名称注入的替代方法.
归档时间: |
|
查看次数: |
221 次 |
最近记录: |