Reputation: 311078
This program
#include <cstddef>
int main()
{
const std::size_t N1 = 2;
const std::size_t N2 = 3;
int ( **p )[N1] = new ( int ( *[N2] )[N1] );
}
does not compile using the compiler C++ gcc HEAD 10.0.0 20190.
The compiler issues error
prog.cc: In lambda function:
prog.cc:8:40: error: expected '{' before ')' token
8 | int ( **p )[N1] = new ( int ( *[N2] )[N1] );
| ^
prog.cc: In function 'int main()':
prog.cc:8:34: error: no match for 'operator*' (operand type is 'main()::<lambda()>')
8 | int ( **p )[N1] = new ( int ( *[N2] )[N1] );
prog.cc:8:47: error: expected type-specifier before ';' token
8 | int ( **p )[N1] = new ( int ( *[N2] )[N1] );
| ^
However the program compiles using clang HEAD 10.0.0.
Is the pointer type-id specification ambiguous or is it indeed a gcc bug?
EDIT: By the way if to remove the outer parentheses like
int ( **p )[N1] = new int ( *[N2] )[N1];
then clang also issues an error referencing a lambda
prog.cc:8:38: error: expected body of lambda expression
int ( **p )[N1] = new int ( *[N2] )[N1];
^
Upvotes: 3
Views: 191
Reputation: 303517
This may not be the answer you're looking for, but the real answer is:
using T = int(*)[N1];
T *p = new T[N2];
The declarator-based syntax that C and C++ use is practically impossible to understand once you have multiple declarators. They're hard to write... where do you put the parentheses? What's the order? And they're hard to read... can't go left-to-right, can't go right-to-left, have to spiral inside-out.
Just use aliases. Easy to write, easy to read, easy to parse.
Upvotes: 1
Reputation: 20619
As far as I can tell, this is definitely a bug in the newest versions of GCC. Presumably, GCC is attempting to parse the ( int ( *[N2] )[N1] )
part as a new-placement, i.e., a parenthesized expression list. Now int (
is interpreted as a function-style cast, etc.
Per new-expression:
new-expression:
::
optnew
new-placementopt new-type-id new-initializeropt
::
optnew
new-placementopt(
type-id)
new-initializeropt
There is no special disambiguation rule regarding new-placement vs (
type-id )
, so the thing should be interpreted as a type-id if it cannot be interpreted as an expression-list.
The EDIT part is a syntax error per [expr.new]/4:
[ Note: Parentheses in a new-type-id of a new-expression can have surprising effects. [ Example:
new int(*[10])(); // error
is ill-formed because the binding is
(new int) (*[10])(); // error
Instead, the explicitly parenthesized version of the new
operator can be used to create objects of compound types:
new (int (*[10])());
allocates an array of 10 pointers to functions (taking no argument and returning int
).
— end example ]
— end note ]
Upvotes: 1