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

时间:2014-05-23 03:53:49

标签: c++ friend

考虑标准sec 3.4.1 / 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(){ }

1 个答案:

答案 0 :(得分:6)

(在我的C ++ 11文档版本中,示例在3.4.1 / 3中提供)。

3.4.1 / 3明确指出,为了解析,为了执行初始确定这是一个后缀表达式还是函数调用,通常执行名称查找。 &#34;平时&#34;表示按3.4.1的其余部分所述执行查找,并且在该初始阶段使用 no ADL 。 3.4.1 / 3明确表示&#34; 3.4.2中的规则对表达式的句法解释没有影响。&#34; (3.4.2是ADL)。

在此示例中,在解析f(a)时,通常的查找用于查找名称f。它找到全局typedef-name ::f,而不是其他任何内容。这意味着f(a)被视为后缀表达式(强制转换),而不是函数调用。请注意,f 中的函数A的朋友声明将引用到函数N::f,但它没有向N::f引入N的声明1}}。由于N::f函数未在N中显式声明(在N中不可见),因此通常的查找不会看到它。它只能看到全局::f,它是一个typedef-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.1 / 3中的一个例子,它基本上等同于你的第二个例子。即标准中的例子是不正确的。这被报告为{{ 3}}标准。)