考虑以下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 的替代方案之一,并且会在此处为我们提供预期的解析。
答案 0 :(得分:2)
虽然我没有权威的答案,但我有一个有根据的猜测。
define-type-specifier 生产最近被添加到标准中:如果你看一个draft from late 2015,它就不存在了,在它出现之前, 类型说明符 将类说明符作为其替代方案之一。
引入定义类型说明符生成的change是DR 2141的解析,它关注 - 等待它 - 涉及 new的模糊性-expression 带有详细类型说明符(虽然它没有特别提到条件表达式)。
对于DR 2141,Clang的implementation status目前被列为"未知"。
所以,我受过教育的猜测是:
我仍然有点困惑的一点是:即使尝试解析类说明符失败,为什么不回溯并尝试解析详细说明类型 - 说明符而不是?据推测,有必要消除 class-specifier 和 elaborated-type-specifier 的歧义,以便在允许其中任何一个的上下文中开始。
答案 1 :(得分:0)
在C ++中struct
与class
相同,只是初始范围为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;
不会引起任何问题,因为后面跟着分号,而不是冒号,因此不需要加括号。