问题
Consider an example from the standard 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)
is postfix expression. How does compiler determine that f(a)
is not a function call? I'm wondering when we have no error like f previously declared of typedef int f
; as in the following example:
#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:
(In my version of the C++11 document the example is presented in 3.4.1/3).
The 3.4.1/3 clearly states that for the purposes of parsing, in order to perform the initial determination of whether this is a postfix expression or function call, a usual name lookup is performed. "Usual" means that the lookup is performed as described in the rest of 3.4.1 and no ADL is used at that initial stage. 3.4.1/3 explicitly says that "The rules in 3.4.2 have no effect on the syntactic interpretation of an expression." (3.4.2 is ADL).
In this example, while parsing f(a)
the usual lookup is used to look for name f
. It finds the global typedef-name ::f
and nothing else. This means that f(a)
is treated as a postfix expression (a cast), not as a function call. Note, that friend declaration of function f
inside A
refers to function N::f
, but it does not introduce a declaration of N::f
into N
. Since N::f
function is not explicitly declared in N
(it is not visible in N
), the usual lookup does not see it. It only sees the global ::f
, which is a typedef-name.
If you want the usual name lookup to find the function in the first example, you have to declare that function in N
explicitly
typedef int f;
namespace N
{
struct A; // <- added
void f(A &); // <- added
struct A
{
friend void f(A &);
...
Now the declaration of N::f
is visible in N
. Now the usual name lookup will find N::f
and treat that f(a)
as a function call from the very beginning.
Your second example is seriously different from the first. You have no extra namespace there. Because of that the friend function declaration in B
refers to the global ::foo
and claims that foo
is a function. But the global ::foo
is already declared as a typedef-name. This contradiction is exactly what causes the error.
(Amusingly, C++03 version of the standard contained an example in 3.4.1/3, which was essentially equivalent to your second example. I.e. the example in the standard was ill-formed. This is reported as Defect #139 of the standard.)
来源:https://stackoverflow.com/questions/23820709/unqualified-name-lookup-applied-instead-of-argument-dependent-name-lookup