Most unpleasant parsing and reversal of the pointer / dereferencing

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

It was expected that at least A((*p)) would call A::A(int=0) . Even adding a few curly braces around *p , treats the operator as A *p; .
The same is true for the operator foo , where the constructor A::A(int=0) not called. Here is a demon.

Question :

  • Why are even (2) and (4) treated as ads?
  • What are the descriptions of foo in operators (3) and (4)?
+4
source share
2 answers

When parsing a construct, which can be either a declaration, or an expression known as the uncertainty of most Vexing Parse, the standard states that “permission should consider any construct that can be a declaration of declaration”.

Both (2) and (4) are valid declarations, therefore they should be analyzed as declarations. Both (3) and (4) declare a function foo function of type A*() aka "that does not pass a pointer to A "

6.8 Ambiguity resolution [stmt.ambig]

There is ambiguity in the grammar, including statement expressions and declarations: an expression-expression with an explicit type conversion in the style of the function (5.2.3) as its left-most subexpression may be indistinguishable from the declaration in which the first declarator begins with a. In these cases, the operator is the declaration. [Note. To resolve the ambiguity, the entire query may need to be examined to determine if it is an expression expression or declaration. This is a multitude of examples. [Example: it is assumed that T is a specifier of a simple type (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, of course, is informal for semantic reasons, but it does not affect the parsing. -end example]

8.2 Ambiguity resolution [dcl.ambig.res]

Uncertainty arising from the similarity between function style coercion and the declaration mentioned in 6.8 may also arise in the context of the declaration. In this context, the choice is between declaring a function with an excessive set of parentheses around the parameter name and declaring the object using the style function as an initializer. In the same way as for the ambiguities mentioned in 6.8, it is permitted to consider any construction that may be a declaration of a declaration . [Note: the declaration can be explicitly eliminated using an ineffective style using a = to indicate initialization or by removing 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]

+1
source

Why are even (2) and (4) treated as ads?

Brackets in declarations can be used to change the order of association in declarations and, possibly, change the meaning of a construct from declaration to expression. They have the same priority as [] , and are grouped from left to right.

For instance:

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

Now, if you count A*p; and A(*p); , parentheses are redundant here because they do not change the way the analysis is done. Adding more of them does not change anything - this is still a valid declaration.

What are the descriptions of foo in operators (3) and (4)?

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

+1
source

Source: https://habr.com/ru/post/1494735/


All Articles