为什么通过ADL成功找到好友功能

时间:2014-05-23 13:52:37

标签: c++ friend

请考虑以下代码:

#include <stdio.h>

class A
{
public:
    friend void foo(A a){ printf("3\n"); }
};

int main()
{ 
    foo(A());
}

有效。但我认为这段代码无效。这是因为3.4.1 / 3:

  

用于确定(在解析期间)表达式是否为   函数调用的后缀表达式,通常的名称查找规则   应用

通常的名称查找规则找不到友元函数,因为朋友声明的名称在我的情况下在全局命名空间中是不可见的。实际上3.3.1 / 4:

  

朋友声明(11.3)可能会引入(可能不可见)名称   进入封闭的命名空间

这意味着该程序是不正确的。这是因为在确定期间找不到名称foo(A());是函数调用的后缀表达式。

我很困惑......

1 个答案:

答案 0 :(得分:4)

解析以下程序时

#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

  

用于确定(在解析期间)表达式是否为   函数调用的后缀表达式,通常的名称查找规则   应用

这意味着:要确定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。

朋友声明会在您发布(3.3.1 / 4)

时引入(可能不可见)名称
  

朋友声明(11.3)可能会引入(可能不可见)名称   进入封闭的命名空间

这意味着以下代码无效

#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
}

您可能想要搜索&#34; 朋友名称注入&#34;和/或Barton-Nackman trick。 简短的故事:现在普通的查找无法找到朋友声明。

因此,您发布的代码格式正确,因为ADL允许它按照我在前面的段落中解释的那样运行。