在c++ 11的SO上回答这个问题的过程中,我意识到在c++ 03中(以及在C中),在常量表达式中明确禁止使用逗号操作符。
c++ 03标准关于常量表达式的第5.19/1段说:
然而,在c++ 11中,最后提到逗号操作符的部分似乎消失了。尽管c++ 11标准第5.19/2段明确规定,赋值、自增、自减和非[…特别地,除了sizeof表达式、函数、类对象、指针或不能使用引用,赋值、自增、自减、函数调用或逗号操作符.
constexpr
函数调用表达式不得作为常量表达式的子表达式出现,但逗号操作符的使用似乎不再被禁止了。
例如,下面的程序在GCC 4.7.2和Clang 3.3中使用std=c++11
可以很好地编译(除了编译器警告说逗号操作符不起作用并且x
和arr
变量未被使用):
int main()
{
constexpr int x = (0, 42);
int arr[(0, 42)];
}
然而,必须指出的是,即使下面的程序使用-std=c++03
选项(Clang和GCC)也可以很好地编译,这显然是不正确的,因为上面引用了c++ 03标准:
int main()
{
int arr[(0, 42)];
}
问题:
是否有c++ 03和c++ 11之间的差异,是否允许在常量表达式中使用逗号操作符,或者我错过了什么?
作为一个额外的(非建设性的)问题,我想知道为什么在c++ 03中不能在常量表达式中使用逗号操作符。
-
是的,我相信这是c++ 03和c++ 11之间的变化。我相信这样做的原因大致与您提到的原因相同——逗号操作符不能作为常量表达式的一部分并没有特别好的理由。
-
我相信c++ 03中的规则起源于C (C90,§6.4)中的规则:
常量表达式不得包含赋值、自增、自减、函数调用或逗号操作符,除非这些操作符包含在sizeof操作数内。
关于C中常量表达式为什么禁止逗号操作符,我只能推测。我的直接猜测是确保像
这样的定义int x[5, 2];
…会被拒绝。如果允许,它可能会导致程序员错误地认为他定义了一个5x2元素的数组(总共10个元素),而(如果这里允许逗号操作符)他实际上只定义了2个元素的x
(并且5
实际上被完全忽略了)。
至于为什么c++委员会认为这是比C委员会更可接受的风险,我猜这可以归结为一个相当简单的情况:C几乎没有提供任何替代方案,因此数组使用得相当多。另一方面,c++同时提供了std::array
和std::vector
,因此很少有理由使用"原始"数组的情况,因此问题不太可能出现。
然而,必须指出的是,即使下面的程序使用-std=c++03选项(在Clang和GCC上)也能很好地编译,这显然是不正确的,因为上面引用了c++03标准
别那么快。您还需要使用-pedantic
(或-pedantic-errors
)来使Clang和GCC严格执行c++ 03规则。这样,GCC主干说:
<stdin>:1:16: error: array bound is not an integer constant before ‘]’ token
和Clang trunk说:
<stdin>:1:19: error: variable length arrays are a C99 feature [-Werror,-Wvla-extension]
void f() { int arr[(0, 42)]; }
^
正如您注意到的,这段代码是有效的c++ 11。然而,在c++ 11中,顶层的逗号仍然是无效的,因为c++ 11语法中的常量表达式是一种条件表达式(顶层的逗号是不允许的)。因此:
int arr[0, 42];