带多单词类型名的{表达式列表}写法是否符合C++语法规范?
(long long){1};是合法的C++代码 示例代码:
(long long){1};
从你给出的标准条款片段分析,这段代码容易被误认为不合法,原因如下:
1. 不符合C风格强制转换的定义
根据[expr.cast]/1的规定,C风格强制转换的语法为(T) cast-expression,其中cast-expression仅能是一元表达式或嵌套的C风格转换表达式。{1}属于初始化列表,不属于cast-expression的范畴,因此这段代码不是C风格强制转换。
表达式(T) cast-expression的结果类型为T。若T为左值引用类型或指向函数的右值引用类型,则结果为左值;若T为指向对象的右值引用类型,则结果为x值;否则结果为纯右值。
cast-expression(强制转换表达式):
- unary-expression(一元表达式)
- ( type-id ) cast-expression
2. 看似不符合函数式强制转换的定义
根据[expr.type.conv]/1的描述,函数式强制转换需以simple-type-specifier或typename-specifier开头,而(long long)是带括号的类型名,不在你列出的simple-type-specifier列表中,因此看起来也不符合函数式转换的要求。
simple-type-specifier(简单类型说明符)或typename-specifier(类型名说明符)后跟带括号的可选表达式列表或带大括号的初始化列表(初始化器),会根据初始化器构造指定类型的值。若类型是推导类类型的占位符,则在本子条款的剩余部分中,它会被通过类模板推导的重载决议所选函数的返回类型替换。否则,若类型包含占位符类型,则会被占位符类型推导([dcl.type.auto.deduct])确定的类型替换。
simple-type-specifier:
- nested-name-specifieropt type-name
- nested-name-specifier template simple-template-id
- decltype-specifier
- placeholder-type-specifier
- nested-name-specifieropt template-name
- char
- char8_t
- char16_t
- char32_t
- wchar_t
- bool
- short
- int
- long
- signed
- unsigned
- float
- double
- void
实际合法的原因
这段代码的合法性来自C++标准对函数式强制转换语法的完整定义——你引用的[expr.type.conv]条款文本描述未涵盖全部语法规则。在标准的语法定义中,函数式强制转换不仅支持simple-type-specifier和typename-specifier,还支持parenthesized-type-id(带括号的类型id)。
函数式强制转换的完整语法为:
functional-type-conversion:
simple-type-specifier ( expression-listopt )
simple-type-specifier braced-init-list
typename-specifier ( expression-listopt )
typename-specifier braced-init-list
parenthesized-type-id ( expression-listopt )
parenthesized-type-id braced-init-list
(long long)属于parenthesized-type-id,后续的{1}是braced-init-list,完全符合上述语法规则。这种写法本质是通过列表初始化进行显式类型转换,会构造一个值为1的long long临时对象,因此是合法的C++代码。
内容的提问来源于stack exchange,提问作者Blackteahamburger

