c – 最令人烦恼的解析和指针间接/解除引用

最小代码:

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.

题:

>为什么甚至(2)和(4)被视为声明?
>陈述(3)和(4)中对foo的描述是什么?

最佳答案 在解析可能是声明或表达式的构造时 – 称为最令人烦恼的解析歧义 – 标准说“解决方案是考虑任何可能是声明声明的构造”.

(2)和(4)都是有效的声明,因此必须将它们解析为声明. (3)和(4)都声明了一个类型为A *()的函数foo,即“函数不带参数返回指向A的指针”

6.8歧义解决[stmt.ambig]

There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion (5.2.3) as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration. [Note: To disambiguate, the whole statement might have to be examined to determine if it is an expression-statement or a declaration. This disambiguates many examples. [Example: assuming T is a simple-type-specifier (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

In the last example above, g, which is a pointer to T, is initialized to double(3). This is of course illformed for semantic reasons, but that does not affect the syntactic analysis. —end example]

8.2歧义解决[dcl.ambig.res]

The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 6.8 can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in 6.8, the resolution is to consider any construct that could possibly be a declaration a declaration. [Note: a declaration can be explicitly disambiguated by a nonfunction-style cast, by a = to indicate initialization or by removing the redundant parentheses around the parameter name. ] [Example:

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]

点赞