"Int size = 10;" дают постоянное выражение?

Следующий код компилируется под gcc 4.8 и Clang 3.2:

int main()
{
  int size = 10;
  int arr[size];
}

8.3.4/1 стандарта С++ говорит, что размер массива должен быть интегральным постоянным выражением, которое size, похоже, не является. Это ошибка в обоих компиляторах, или я чего-то не хватает?

Последний VС++ CTP отклоняет код с помощью этого интересного сообщения:

error C2466: cannot allocate an array of constant size 0

Интересная часть состоит в том, как кажется, что size равно нулю. Но, по крайней мере, он отвергает код. Должны ли gcc и Clang делать то же самое?

Ответ 1

Это массивы переменной длины или VLA, который является функцией C99, но gcc и clang поддерживают его как расширение в С++, а Visual Studio не. Таким образом, Visual Studio придерживается стандарта в этом случае и является технически правильным. Не говоря уже о том, что расширения плохие, Ядро Linux зависит от многих расширений gcc, поэтому они могут быть полезны в определенных контекстах.

Если вы добавите флаг -pedantic, как gcc, так и clang предупредит вас об этом, например gcc говорит (посмотреть его жить):

warning: ISO C++ forbids variable length array 'arr' [-Wvla]
  int arr[size];
              ^

Использование флага -pedantic-errors сделает ошибку. Вы можете больше узнать о расширениях в этих документах Языковые стандарты, поддерживаемые GCC и clangs Language Compatibility раздел.

Обновить

черновик стандарта С++ охватывает то, что является интегральным постоянным выражением в разделе 5.19 Константы выражений, параграф 3, и говорит:

Интегральное постоянное выражение представляет собой выражение интегрального или неперечисленного типа перечисления, неявно преобразованного в prvalue, где преобразованное выражение является выражением постоянной константы. [...]

Это не интуитивно очевидно из чтения этого, что все возможности, но Boost Coding Guidelines для интегральных константных выражений отлично справляется с этим.

В этом случае, поскольку вы инициализируете size литералом с использованием const, достаточно сделать его интегральным постоянным выражением, а также вернуть код в стандартную С++:

const int size = 10;

использование constexpr тоже будет работать:

constexpr int size = 10;

Возможно, это поможет прочитать Разницу между constexpr и const.

Для справки эквивалентная секция в 8.3.4, параграф 1 в черновик проекта C99 будет секцией 6.7.5.2 абзацев абзацев 4, которые говорит (внимание мое):

Если размер отсутствует, тип массива является неполным. Если размер равен * вместо выражения, тип массива - это тип массива переменной длины неопределенного размера, который может использоваться только в объявлениях с областью прототипа функции; 124) такие массивы, тем не менее, завершены типы. Если размер представляет собой целочисленное константное выражение, а тип элемента имеет известный постоянный размер, тип массива не является массивом переменной длины; , в противном случае тип массива - это тип массива переменной длины.