一个关于朋友函数名字查找的问题

jac*_*k X 5 c++ friend language-lawyer name-lookup c++17

我已经阅读了 [basic.lookup.unqual] 的标准部分,我对此感到困惑:

typedef int f;
namespace N {
  struct A {
    friend void f(A &);
    operator int();
    void g(A a) {
      int i = f(a);  // f is the typedef, not the friend function: equivalent to int(a)
    }
  };
}
Run Code Online (Sandbox Code Playgroud)

请考虑上面的代码;我不明白为什么 namef是 type int,而不是void f(A &). 在我的理解中,名称查找应该void f(A &)首先在类范围 A 中找到。如果在那里找不到名称,它将在外部命名空间中执行查找。显然,void f(A &)课堂上有一个名字A,正如标准所说:

一旦找到名称的声明,名称查找就结束

那么为什么int这里的名称指的是类型,如果有关于这些的其他特定规则呢?

son*_*yao 6

首先,朋友声明本身f对于名称查找不可见,f只能由 ADL 找到。

首先在类或类模板 X 中的友元声明中声明的名称成为 X 的最内部封闭命名空间的成员,但对于查找不可见(考虑 X 的依赖于参数的查找除外),除非命名空间范围内的匹配声明是假如

从标准,[namespace.memdef]/3

友元声明本身不会使名称对非限定查找或限定查找可见。[注意:如果在命名空间范围内(在授予友谊的类定义之前或之后)提供匹配声明,则朋友的名称将在其命名空间中可见。— end note ] 如果调用友元函数或函数模板,则可以通过名称查找找到其名称,该名称查找考虑来自与函数参数类型([basic.lookup.argdep])关联的命名空间和类的函数。如果友元声明中的名称既不是限定名称也不是模板 id 并且声明是函数或详细类型说明符,则确定实体之前是否已声明的查找不应考虑最内部封闭命名空间之外的任何范围.

问题是要应用ADL,f(a)必须事先确定是否是函数调用。

[basic.lookup.unqual]/3 ,

(强调我的)

[basic.lookup.argdep] 中描述了对用作函数调用后缀表达式的非限定名称的查找。[注意:为了确定(在解析期间)表达式是否是函数调用的后缀表达式,通常的名称查找规则适用

在这个阶段,函数名f是不可见的,类型名是f被发现的,那么f(a)就认为不是一个函数all,那么ADL根本就不会被应用。

由于该表达式不是函数调用,因此参数相关名称查找 ([basic.lookup.argdep]) 不适用且未找到友元函数 f。

顺便说一句:添加fat 命名空间范围的声明会使函数名称f可见,f(a)并将被视为函数调用(然后您将得到f返回的错误,该错误void不能用于 initialize i)。例如

typedef int f;
namespace N {
  struct A;
  void f(A &);
  struct A {
    friend void f(A &);
    operator int();
    void g(A a) {
      int i = f(a);  // f is the friend function now
    }
  };
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,一个精彩的答案。因为“朋友声明本身并不使名称对不合格查找或合格查找可见”和“为了确定,应用通常的名称查找规则”(指不合格查找),所以, “不合格查找”找不到`friend function`,只能找到typedef,所以没有ADL继续执行,我的理解对吗? (3认同)