18

Consider the following piece of code:

#include <iostream>
using namespace std;

int main()
{
    int x = 3;
    const int i[] = { 1, 2, 3, 4 };
    float f[i[3]]; 
    struct S { int i, j; };
    const S s[] = { { 1, 2 }, { 3, 4 } };
    double d[s[1].j];
}

It runs without error. However, the following:

#include <iostream>
using namespace std;


int x = 3;
const int i[] = { 1, 2, 3, 4 };
float f[i[3]]; // error: array bound is not an integer constant before ']' token|
struct S { int i, j; };
const S s[] = { { 1, 2 }, { 3, 4 } };
double d[s[1].j]; // error: array bound is not an integer constant before ']' token|

int main()
{
    return 0;
}

Does not, as it gets the errors that are highlighted as comments. Can anyone explain to me why that is?

ruakh
  • 175,680
  • 26
  • 273
  • 307
George Cernat
  • 1,323
  • 9
  • 27
  • 2
    I think it is because i[3] is not constant, what is constant is i[] it means that i[] can not point to any other chunk of memory, but you can still change each element within i. – apalomer Aug 29 '17 at 19:40
  • 3
    One guess is that you use g++ [which has an extension for VLAs](https://stackoverflow.com/questions/5947661/in-c-books-array-bound-must-be-constant-expression-but-why-the-following-cod) and doesn't require local array bounds to be constant. – Bo Persson Aug 29 '17 at 19:46
  • 2
    Note that the first is also invalid in standard C++, but your compiler allows it as an extension. – Daniel H Aug 29 '17 at 19:46
  • I get lots of warnings for the first example. – wally Aug 29 '17 at 19:46
  • 3
    With correct compiler settings first code sample will also fail to compile src/test.cpp: In function ‘int main()’: src/test.cpp:8:17: error: ISO C++ forbids variable length array ‘f’ [-Werror=vla] float f[i[3]]; – Artemy Vysotsky Aug 29 '17 at 19:58

2 Answers2

19

More than likely, the reason the compiler allows it within the function is due to a compiler extension: variable-length arrays. They allow arrays declared inside of functions to have non-constexpr lengths. But it only works inside of functions, not at global scope.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
17

You have to use constexpr instead of const

constexpr int i[] = { 1, 2, 3, 4 };
constexpr S s[] = { { 1, 2 }, { 3, 4 } };

const applies for variables, and prevents them from being modified in your code.

constexpr tells the compiler that this expression results in a compile time constant value, so it can be used in places like array lengths, assigning to const variables, etc.

Reason why it does compile in funcion is VLA. Its not possible to declare VLA in global scope.

6.7.6.2 Array declarators

2 If an identifier is declared as having a variably modified type, it shall be an ordinary identifier (as defined in 6.2.3), have no linkage, and have either block scope or function prototype scope. If an identifier is declared to be an object with static or thread storage duration, it shall not have a variable length array type.

Also VLAs are not part of standard, its only compiler extension here.

kocica
  • 6,412
  • 2
  • 14
  • 35
  • 7
    While this is a perfectly valid solution, it doesn't explain the compiler error. – R Sahu Aug 29 '17 at 19:44
  • 2
    It's not because the same construct works when used inside the function. – R Sahu Aug 29 '17 at 19:44
  • Not the down voter but one issue is a regular `const int` [can be used for an array size](http://coliru.stacked-crooked.com/a/b82c88add207cc84). This makes the answer a little trickier. I'm inclined to go with Nicol on this and that the extension just has some limitations and one of those is not being able to use and array element. – NathanOliver Aug 29 '17 at 20:01
  • Although you do say *Reason why it does compile in funcion is VLA. Its not possible to declare VLA in global scope.* so IDK. – NathanOliver Aug 29 '17 at 20:02