Why does friend function found successfully via AD

2020-07-24 21:46发布

Consider the following code:

#include <stdio.h>

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

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

It works. But I thought that this code is invalid. It is because 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.

Usual name lookup rules could not find the friend function because name declared by friend is invisible in the global namespace in my case. Actually 3.3.1/4:

friend declarations (11.3) may introduce a (possibly not visible) name into an enclosing namespace

This implies that the programm is ill-formed. It is because that there is no name which found during the determining is the expression foo(A()); is a postfix-expression for a function call.

I'm confusing...

标签: c++ friend
1条回答
冷血范
2楼-- · 2020-07-24 22:08

When parsing the following program

#include <iostream>
using namespace std;

typedef int foo;

class A
{
public:
   operator int(){
    return 42;
   }
};

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

the output will be 42 because 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.

that means: to determine if foo is a postfix-expression (e.g. a cast) or a function call, the compiler will first use name lookup and search for it in the global namespace and/or enclosing scopes / base classes (or with fully qualified lookups if available).

Now take this code:

#include <iostream>
using namespace std;

class A
{
public:
   friend int foo(A a){ return 55; }

   operator int(){
    return 42;
   }
};

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

The above will output 55 thanks to ADL: foo will be found by searching inside the scopes defined by its potential arguments, i.e. A.

A friend declaration introduces a (possibly not visible) name as you posted (3.3.1/4)

friend declarations (11.3) may introduce a (possibly not visible) name into an enclosing namespace

that means the following code will not work

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

You might want to search for "friend name injection" and/or the Barton-Nackman trick. Short story: now ordinary lookups can't find friend declarations.

So the code you posted is well-formed because ADL allows it to run as I explained in the previous passages.

查看更多
登录 后发表回答