gcc 相对于在新表达式中解析 type-id 发出错误

An error is issued by gcc relative to parsing type-id in a new expression

这个节目

#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 使用编译器 C++ gcc HEAD 10.0.0 20190.

编译器报错

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] );
      |                                               ^

但是程序使用 clang HEAD 10.0.0 进行编译。

指针 type-id 规范是否有歧义或者它确实是一个 gcc 错误?

编辑:顺便说一句,如果删除外括号,如

int ( **p )[N1] = new int ( *[N2] )[N1];

然后 clang 也会发出引用 lambda 的错误

prog.cc:8:38: error: expected body of lambda expression
   int ( **p )[N1] = new int ( *[N2] )[N1];
                                     ^

据我所知,这绝对是最新版本的 GCC 中的一个错误。据推测,GCC 正试图将 ( int ( *[N2] )[N1] ) 部分解析为 new-placement,即带括号的表达式列表。现在 int ( 被解释为函数式转换等

根据 new-expression:

new-expression:
    ::opt new new-placementopt new-type-id new-initializeropt
    ::opt new new-placementopt ( type-id ) new-initializeropt

new-placement vs ( type-id ) 没有特殊的消歧规则,所以如果它不能被解释为 expression-list.

,它应该被解释为 type-id

EDIT 部分是语法错误 [expr.new]/4:

[ 注意: new-type-id 中的括号 new-expression 可以产生惊人的效果。 [ 示例:

new int(*[10])();               // error

格式错误,因为绑定是

(new int) (*[10])();            // error

相反,new 运算符的显式括号版本可用于创建复合类型的对象:

new (int (*[10])());

分配一个包含 10 个函数指针的数组(不带参数并返回 int)。 — 结束示例] — 尾注]

这可能不是您要找的答案,但真正的答案是:

using T = int(*)[N1];
T *p = new T[N2];

一旦拥有多个声明符,C 和 C++ 使用的基于声明符的语法实际上就无法理解。它们很难写......你把括号放在哪里?顺序是什么?而且它们很难阅读...不能从左到右,不能从右到左,必须从内到外螺旋。

就用别名吧。易于编写,易于阅读,易于解析。