Example
int main()
{
const int i = 1.0; // Notice I am assigning a double to an int here
char a[i];
}
Question
Compiling the above code with g++ -O0 -Wall -pedantic -ansi -std=c++11
gives no errors (except for an unused variable). However, if I remove -std=c++11
, I get the following warning:
warning: ISO C++ forbids variable length array
According to this SO question, I believe that in C++03, the code is invalid. However, can someone explain how the rule has changed in C++11?
(This question was a result of a previous question I answered.)
The simplest form of floating point literal consists of one or more decimal digits and a decimal point ( . ) and an optional suffix ( f , F , d or D ). The optional suffix allows you to specify that the literal is a float ( f or F ) or double ( d or D ) value. The default (when no suffix is specified) is double .
Floating-point literals are numbers that have a decimal point or an exponential part. They can be represented as: Real literals. Binary floating-point literals. Hexadecimal floating-point literals (C only)
A floating-point literal has an integer part, a decimal point, a fractional part, and an exponent part. You can represent floating point literals either in decimal form or exponential form.
Floating-point literals are values that contain a decimal point in between them. Floating-point literals are generally double data type by default. We can assign them to float data types by adding an f at the end of the value.
An array bound must be an integral constant expression, see 8.3.4 [dcl.array]/1 (same wording in C++03 and C++11):
If the constant-expression (5.19) is present, it shall be an integral constant expression and its value shall be greater than zero.
In C++03 an integral constant expression cannot be initialized by a floating literal unless cast to integral type, see the last sentence of 5.19 [expr.const]/1:
An integral constant-expression can involve only literals (2.13), enumerators,
const
variables or static data members of integral or enumeration types initialized with constant expressions (8.5), non-type template parameters of integral or enumeration types, andsizeof
expressions. Floating literals (2.13.3) can appear only if they are cast to integral or enumeration types.
This means that in C++03 i
is not an integral constant expression, so cannot be used as an array bound.
GCC and Clang allow variable-length arrays as an extension to C++03, so it compiles with a non-constant bound, but you get a warning with -pedantic
. Changing the constant's initializer to cast it to integral type makes i
a valid integral constant expression:
const int i = (int) 1.0;
With that change the array is no longer variable length and there is no warning even with -pedantic
.
In C++11 5.19 [expr.const]/3 says:
A literal constant expression is a prvalue core constant expression of literal type, but not pointer type. An integral constant expression is a literal constant expression of integral or unscoped enumeration type.
The preceding (quite lengthy) paragraphs describe the rules for core constant expressions, but basically in C++11 the double initializer does not prevent i
being a core constant expression, even without a cast, so it is an integral constant expression and therefore a valid array bound, so no warning.
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