考虑标准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(){ }
答案 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}}标准。)