考虑以下代码:
#include <stdio.h>
class A
{
public:
friend void foo(A a){ printf("3\n"); }
};
int main()
{
foo(A());
}
它有效。但我认为这段代码无效。这是因为 3.4.1/3:
For purposes of determining (during parsing) whether an expression is a postfix-expression for a function call, the usual name lookup rules apply.
通常的名称查找规则无法找到 friend 函数,因为在我的例子中,friend 声明的名称在全局命名空间中是不可见的。实际上 3.3.1/4:
friend declarations (11.3) may introduce a (possibly not visible) name into an enclosing namespace
这意味着程序格式错误。这是因为没有找到名字,在确定表达式foo(A());
是一个函数调用的后缀表达式。
我很困惑......
最佳答案
解析如下程序时
#include <iostream>
using namespace std;
typedef int foo;
class A
{
public:
operator int(){
return 42;
}
};
int main()
{
cout << foo(A());
}
输出将为 42
因为 3.4.1/3
For purposes of determining (during parsing) whether an expression is a postfix-expression for a function call, the usual name lookup rules apply.
这意味着:要确定 foo
是后缀表达式(例如强制转换)还是函数调用,编译器将首先使用名称查找并在全局命名空间和/或封闭范围/基类(或如果可用,使用完全限定的查找)。
现在使用这段代码:
#include <iostream>
using namespace std;
class A
{
public:
friend int foo(A a){ return 55; }
operator int(){
return 42;
}
};
int main()
{
cout << foo(A());
}
感谢ADL,以上将输出55
: foo 将通过在其潜在参数定义的范围内搜索找到,即 A.
friend 声明在您发布 (3.3.1/4) 时引入了一个(可能不可见的)名字
friend declarations (11.3) may introduce a (possibly not visible) name into an enclosing namespace
这意味着下面的代码将不起作用
#include <iostream>
using namespace std;
class A
{
public:
friend int foo(A a){ return 55; }
operator int(){
return 42;
}
};
int main()
{
cout << ::foo(A()); // Not found
cout << A::foo(A()); // Not found
}
您可能想要搜索“ friend 姓名注入(inject)”和/或 Barton-Nackman trick . 简短的故事:现在普通查找找不到友元声明。
所以您发布的代码格式正确,因为 ADL 允许它按照我在前面的段落中解释的那样运行。
关于c++ - 为什么通过ADL成功找到 friend 功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23831077/