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...
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.