带const限定的临时对象用作数组下标时,加括号可编译而不加则报错的原因探究
这问题问得挺接地气的,咱们从C++的语法规则和编译器实现细节两方面来拆解:
先看为什么c1会报错
你写的v[const size_t{ 2 }],核心问题出在C++对数组下标运算符[]内部表达式的语法要求上。
C规定,E1[E2]等价于*(E1 + E2),所以E2必须是一个合法的表达式。但const size_t{2}这种写法,在标准C里根本不是一个合法的表达式:const在这里试图直接修饰一个临时对象的类型,但这个上下文里,编译器期望的是一个能求值的表达式,而不是带const限定的类型构造语法。MSVC看到const直接出现在[]里,会直接判定为语法错误——它不知道该把这个const归到哪里,所以抛出了C2059、C2143这类语法错误。
为什么MSVC会接受c2?
当你给const size_t{2}套上括号变成(const size_t{ 2 })时,情况就变了:括号会强制编译器把内部内容当成一个独立的表达式上下文来解析。
这里要注意:这其实是MSVC的一个非标准扩展。标准C++里,哪怕加了括号,const size_t{2}也不是合法的表达式——你没法直接通过这种语法构造一个带const限定的临时对象。但MSVC额外支持了这个写法,在括号的表达式上下文中,它允许你用const T{...}的形式创建const临时对象,所以v[(const size_t{ 2 })]在MSVC里能编译通过。
为什么其他编译器(比如GCC)连c2都拒绝?
像GCC、Clang这类编译器是严格遵循C++标准的,它们不支持MSVC的这个非标准扩展。在标准语法里,const size_t{2}不管加不加括号,都不是合法的表达式,所以这类编译器会直接报错,和MSVC的行为形成差异。
最后看c3为什么全平台合法
static_cast<const size_t>(2)是标准C++规定的合法语法——它通过显式的类型转换,明确地把值2转换成const size_t类型的临时对象,所有符合标准的编译器都能正确解析这种写法,这也是创建const限定临时对象的标准方式。
说白了,你遇到的差异本质上是MSVC的非标准扩展和标准C++语法规则的冲突,括号的作用只是改变了编译器的解析上下文,让MSVC的扩展机制能生效而已。
内容来源于stack exchange

