应用非限定名称查找,而不是依赖参数的名称查找

Unqualified name lookup applied instead of argument-dependent name lookup

本文关键字:查找 参数 依赖 定名称 应用      更新时间:2023-10-16

考虑一个来自标准第3.4.3/3节的例子:

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)
        }
    };
}

f(a)为后缀表达式。编译器如何确定f(a)不是一个函数调用?我想知道我们什么时候没有像f previously declared of typedef int f那样的误差;如下例所示:

#include <stdio.h>
typedef int foo; //error: previous declaration of ‘typedef int foo’
class B
{
public:
    friend void foo(B b){ printf("3"); } //error: ‘void foo(B)’ redeclared as different kind of symbol
    static const int c=42;
};
int main(){ }

(在我的c++ 11文档版本中,示例在3.4.3中给出)。

3.4.3明确指出,为了进行解析,为了执行初始确定这是后缀表达式还是函数调用,执行通常的名称查找。"通常"意味着按照3.4.1其余部分的描述执行查找,并且在初始阶段不使用ADL。3.4.3明确指出"3.4.2中的规则对表达式的语法解释没有影响。"(3.4.2 is ADL).

在本例中,在解析f(a)时,使用常规查找来查找名称f。它查找全局类型定义-name ::f,而没有其他任何内容。这意味着f(a)被视为后缀表达式(强制类型转换),而不是函数调用。注意,A 中的函数f的友元声明指向函数N::f,但它没有在N中引入N::f的声明。由于N::f函数没有在N中显式声明(它在N中不可见),因此通常的查找不会看到它。它只看到全局::f,这是一个类型定义-name。

如果您希望使用通常的名称查找来查找第一个示例中的函数,则必须在N中显式声明该函数

typedef int f;
namespace N 
{
    struct A;     // <- added
    void f(A &);  // <- added
    struct A 
    {
        friend void f(A &);
        ...

现在N::f的声明在N中可见。现在,通常的名称查找将找到N::f,并从一开始就将该f(a)视为函数调用。

你的第二个例子与第一个有很大的不同。这里没有额外的名称空间。因此,B中的友元函数声明引用全局::foo,并声明foo是一个函数。但是全局::foo已经被声明为typedef-name。这个矛盾正是导致错误的原因。

(有趣的是,c++ 03版本的标准在3.4.3/3中包含了一个示例,它本质上等同于您的第二个示例。也就是说,标准中的例子是病态的。这被报告为标准中的缺陷#139)