Domanda

Minimal code:

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) ??
  }
}

Was expecting at least A((*p)) would invoke A::A(int=0). Even putting multiple braces around *p, treats the statement as A *p;.
The same holds true for foo related statement, where the constructor A::A(int=0) is not called. Here is a demo.

Question:

  1. Why are even (2) and (4) being treated as declarations?
  2. What is the descriptions of foo in statements (3) and (4)?
È stato utile?

Soluzione

When parsing a construct that could either be a declaration or an expression - known as the Most Vexing Parse ambiguity - the standard says "the resolution is to consider any construct that could possibly be a declaration a declaration".

Both (2) and (4) are valid declarations, therefore they must be parsed as declarations. Both (3) and (4) declare a function foo of type A*() aka "function taking no parameter returning pointer to A"

6.8 Ambiguity resolution [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 Ambiguity resolution [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]

Altri suggerimenti

Why are even (2) and (4) being treated as declarations?

Parentheses in declarations can be used to change the association order in declarators and possibly change the meaning of the construct from declaration to expression. They have the same precedence as [] and group left to right.

For example:

int*a[1];   // brackets have higher precedence - this is an array of pointers
int(*a)[1]; // pointer to an array

Now if you consider A*p; and A(*p); the parentheses here are redundant because they didn't change the way this is parsed. Adding more of them doesn't change a thing - it is still a valid declaration.

What is the descriptions of foo in statements (3) and (4)?

The declarations are the same as A* foo();

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top