8

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.)

Community
  • 1
  • 1
Jesse Good
  • 50,901
  • 14
  • 124
  • 166
  • Did you mean to make `i` a double, not an int? – David Jun 07 '12 at 04:06
  • @Dave: No, that was on purpose. See the link to the previous question. – Jesse Good Jun 07 '12 at 04:09
  • FWIW, clang++ 3.0 doesn't show the VLA warning. I don't have g++ to test it, but I suppose the warning doesn't go away if you change the assignment to `const int i = 1;`. Does it? – jweyrich Jun 07 '12 at 06:10
  • @jweyrich: Compiling with `-pedantic` on clang++ 3.1 gives a similar warning. If you change it to `const int i = 1;` the warning goes away. – Jesse Good Jun 07 '12 at 06:17

1 Answers1

7

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, and sizeof 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.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • 1
    GCC does *not* warn about the wrong integer constant initialisation. It warns about the use of the VLA compiler extension (which C++11 doesn’t use any more, since in C++11 the array can be initialised by a constant). – Konrad Rudolph Jun 07 '12 at 13:47
  • @Konrad, yeah, just edited it to clarify what I meant by "allows it" – Jonathan Wakely Jun 07 '12 at 13:48