新表达式

时间:2017-10-18 05:13:22

标签: c++ parsing gcc visual-c++ clang

考虑以下C ++代码:

struct A {};
struct A* b = (1 == 1) ? new struct A : new struct A;

MSVC接受了这一点,但GCC和Clang没有。 我想了解根据标准哪个是正确的,为什么。

Clang给出的错误是:

test.cpp:2:37: error: redefinition of 'A'
struct A* b = (1 == 1) ? new struct A : new struct A;
                                    ^
test.cpp:1:8: note: previous definition is here
struct A {};
       ^
test.cpp:2:37: error: '(anonymous struct at test.cpp:2:37)' cannot be defined in a type specifier
struct A* b = (1 == 1) ? new struct A : new struct A;
                                    ^
test.cpp:2:41: error: expected class name
struct A* b = (1 == 1) ? new struct A : new struct A;
                                        ^
test.cpp:2:53: error: expected '{' after base class list
struct A* b = (1 == 1) ? new struct A : new struct A;
                                                    ^
test.cpp:2:53: error: expected ':'
struct A* b = (1 == 1) ? new struct A : new struct A;
                                                    ^
                                                    :
test.cpp:2:24: note: to match this '?'
struct A* b = (1 == 1) ? new struct A : new struct A;
                       ^
test.cpp:2:53: error: expected expression
struct A* b = (1 == 1) ? new struct A : new struct A;
                                                    ^

这告诉我,clang正在尝试将标记struct A :解析为类说明符,冒号引入了 base-clause ,并且然后在解析失败时保释。

但是,我不明白为什么它会尝试解析 class-specifier 。查看latest draft standard new-expression 的语法,它使用 new-type-id 语法生成,它使用 type-specifier- seq ,它使用 type-specifier 。但是, class-specifier type-specifier 的替代方案之一 - 它仅作为 define-type的替代方案出现-specifier 。另一方面, elaborated-type-specifier type-specifier 的替代方案之一,并且会在此处为我们提供预期的解析。

2 个答案:

答案 0 :(得分:2)

虽然我没有权威的答案,但我有一个有根据的猜测。

define-type-specifier 生产最近被添加到标准中:如果你看一个draft from late 2015,它就不存在了,在它出现之前, 类型说明符 类说明符作为其替代方案之一。

引入定义类型说明符生成的changeDR 2141的解析,它关注 - 等待它 - 涉及 new的模糊性-expression 带有详细类型说明符(虽然它没有特别提到条件表达式)。

对于DR 2141,Clang的implementation status目前被列为"未知"。

所以,我受过教育的猜测是:

  • Clang和GCC尚未执行DR 2141的决议
  • 因此,他们正在尝试根据旧的类型说明符生产解析 new-type-id ,其中包含类说明符作为其替代品之一。

我仍然有点困惑的一点是:即使尝试解析类说明符失败,为什么不回溯并尝试解析详细说明类型 - 说明符而不是?据推测,有必要消除 class-specifier elaborated-type-specifier 的歧义,以便在允许其中任何一个的上下文中开始。

答案 1 :(得分:0)

在C ++中structclass相同,只是初始范围为public:而不是private:。因此,一旦您声明struct A {};表达式,引用该类型应仅使用类型标识A,而不使用struct关键字:

A* b = (1 == 1) ? new A : new A;

修改

正如OP在评论中指出的那样,struct A是一个有效的类型名称,因此它可以作为new的参数出现。但是,new表达式中的 type-id 被认为是贪婪的。以下是cppreference.com的示例:

new int + 1 // syntactically okay, '+1' offsets the pointer returned by 'new int'
new int * 1 // error, type (int *) is assumed and 1 doesn't make sense in '(new (int *)) 1'

因此,当编译器在class A之后发现冒号时,它可能会假设完整的声明语法(class A : public base_class)看起来不完整在此处不允许 - 因此{{1消息。

解决方案:通过将其括在括号中来明确界定类型:

error: redefinition of 'A'

注意第二个1 ? new (struct A) : new struct A; 不会引起任何问题,因为后面跟着分号,而不是冒号,因此不需要加括号。