In the process of answering this question on SO for C++11, I realized that in C++03 (as well as in C) the use of the comma operator is explicitly forbidden in a constant-expression.
Paragraph 5.19/1 of the C++03 Standard on constant expressions says:
[...] In particular, except in sizeof expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call, or comma operators shall not be used.
In C++11, however, that last part mentioning the comma operator seems to be vanished. And while paragraph 5.19/2 of the C++11 Standard clearly specifies that assignment, increment, decrement, and non-constexpr
function call expressions shall not appear as sub-expressions of a constant-expression, the usage of the comma operator does not seem to be forbidden anymore.
For instance, the following program compiles fine on GCC 4.7.2 and Clang 3.3 with std=c++11
(apart from compiler warnings saying the comma operator has no effect and the x
and arr
variables are unused):
int main() { constexpr int x = (0, 42); int arr[(0, 42)]; }
However, it must be said that even the following program compiles fine with the -std=c++03
option (both on Clang and GCC), which is clearly not correct, given the above quote from the C++03 Standard:
int main() { int arr[(0, 42)]; }
QUESTION:
Is there a difference between C++03 and C++11 as to whether or not the comma operator is allowed in a constant expression, or am I missing something?
As a bonus (non-constructive) question, I would be interested in knowing why the comma operator cannot be used in a constant expression in C++03.
The comma operator in c comes with the lowest precedence in the C language. The comma operator is basically a binary operator that initially operates the first available operand, discards the obtained result from it, evaluates the operands present after this, and then returns the result/value accordingly.
The comma operator will always yield the last value in the comma separated list. Basically it's a binary operator that evaluates the left hand value but discards it, then evaluates the right hand value and returns it. If you chain multiple of these they will eventually yield the last value in the chain.
A constant expression gets evaluated at compile time, not run time, and can be used in any place that a constant can be used. The constant expression must evaluate to a constant that is in the range of representable values for that type.
In C and C++, comma (, ) can be used in two contexts: 1) Comma as an operator: The comma operator (represented by the token, ) is a binary operator that evaluates its first operand and discards the result, it then evaluates the second operand and returns this value (and type).
Yes, I believe this is a change between C++03 and C++11. I believe it was done for roughly the reason to which you allude -- that there's no particularly good reason a comma operator can't be part of a constant expression.
I believe the rule in C++03 originated from the rule in C (C90, §6.4):
Constant expressions shall not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within the operand of a sizeof operator.
As to why the comma operator was prohibited in constant expressions in C, I can only speculate. My immediate guess would be to assure that a definition like:
int x[5, 2];
...would be rejected. If it were allowed, it could lead the programmer to the mistaken belief that he'd defined a 5x2 element array (for a total of 10 elements), when (if a comma operator were allowed there) he'd really defined x
with only 2 elements (and the 5
was effectively ignored completely).
As to why the C++ committee considered this a more acceptable risk than the C committee, I'd guess it comes down to a fairly simple situation: C provides nearly no alternative, so arrays are used quite a bit. C++, on the other hand, provides both std::array
and std::vector
, leaving extremely few situations in which there's much reason to use a "raw" array, so the problem is a lot less likely to arise.
However, it must be said that even the following program compiles fine with the -std=c++03 option (both on Clang and GCC), which is clearly not correct, given the above quote from the C++03 Standard
Not so fast. You need to also use -pedantic
(or -pedantic-errors
) to get Clang and GCC to strictly enforce the C++03 rules. With that, GCC trunk says:
<stdin>:1:16: error: array bound is not an integer constant before ‘]’ token
and Clang trunk says:
<stdin>:1:19: error: variable length arrays are a C99 feature [-Werror,-Wvla-extension] void f() { int arr[(0, 42)]; } ^
As you note, this code is valid C++11. However, top-level commas are still not valid in C++11, because a constant-expression in the C++11 grammar is a kind of conditional-expression (where a top-level comma is not permitted). Thus:
int arr[0, 42];
is still ill-formed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With