最小代码:
struct A {
A(int = 0) {}
};
int i = 0, *p = &i;
int* foo () { return p; }
int main () {
A(); // calls `A::A(int=0)`
A(i); // calls `A::A(int=0)`
A(*p); // <--- (1) same as local `A *p;`
{
A((*p)); // <--- (2) same as local `A *p;`
}
A (*foo()); // <--- (3) ??
{
A ((*foo())); // <--- (4) ??
}
}
期望至少A((*p))
会调用A::A(int=0)
。即使在*p
周围加上多个括号,也要将该语句视为A *p;
对于foo
相关语句也是如此,其中未调用构造函数A::A(int=0)
。
这是demo。
问题:
foo
的描述是什么?答案 0 :(得分:1)
为什么偶数(2)和(4)被视为声明?
声明中的括号可用于更改声明符中的关联顺序,并可能将构造的含义从声明更改为表达式。它们具有与[]
相同的优先级,并且从左到右分组。
例如:
int*a[1]; // brackets have higher precedence - this is an array of pointers
int(*a)[1]; // pointer to an array
现在,如果你考虑A*p;
和A(*p);
这里的括号是多余的,因为它们没有改变解析它的方式。添加更多它们并不会改变一件事 - 它仍然是一个有效的声明。
语句(3)和(4)中对foo的描述是什么?
声明与A* foo();
答案 1 :(得分:1)
在解析可能是声明或表达式的构造时 - 称为最令人烦恼的解析歧义 - 标准说“解决方案是考虑任何可能是声明的构造声明”。
(2)和(4)都是有效的声明,因此必须将它们解析为声明。 (3)和(4)都声明了foo
类型的函数A*()
,也就是“没有参数返回指向A
的函数”
6.8 Ambiguity resolution [stmt.ambig]
涉及表达式语句和声明的语法存在歧义:具有函数式显式类型转换(5.2.3)的表达式语句,因为其最左侧的子表达式与第一个声明符以第一个声明符开头的声明无法区分a(。在这些情况下,语句是声明。 [注意:为了消除歧义,可能必须检查整个语句以确定它是表达式语句还是声明。这消除了许多示例的歧义。[例子:假设T是一个简单类型说明符(7.1.5),
T(a)->m = 7; // expression-statement
T(a)++; //expression-statement
T(a,5)<<c; //expression-statement
T(*d)(int); //declaration
T(e)[5]; //declaration
T(f) = { 1, 2 }; // declaration
T(*g)(double(3)); // declaration
在上面的最后一个例子中,g是一个指向T的指针,被初始化为double(3)。由于语义原因,这当然是错误的,但这并不影响句法分析。 - 例子]
8.2 Ambiguity resolution [dcl.ambig.res]
函数式转换与6.8中提到的声明之间的相似性所产生的歧义也可能出现在声明的上下文中。在该上下文中,选择在函数声明与参数名称周围的冗余括号集和具有函数样式转换作为初始化器的对象声明之间。正如6.8中提到的含糊不清一样,决议是考虑任何可能是声明声明的构造。 [注意:声明可以通过非函数式转换显式消除歧义,通过a表示初始化或删除参数名称周围的冗余括号。 ] [例子:
struct S {
S(int);
};
void foo(double a)
{
S w(int(a)); // function declaration
S x(int()); // function declaration
S y((int)a); // object declaration
S z = int(a); // object declaration
}
-end example]