Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Инициализация const int литералом с плавающей запятой

Автор вопроса: Jesse GoodОтветов: 1

Пример

int main()
{
    const int i = 1.0; // Notice I am assigning a double to an int here
    char a[i];
}

Вопрос

Компиляция приведенного выше кода с g++ -O0 -Wall -pedantic -ansi -std=c++11 не дает ошибок (за исключением неиспользуемой переменной). Однако, если я удалю -std=c++11, я получу следующее предупреждение:

предупреждение: ISO C++ запрещает массив переменной длины

Согласно этому вопросу SO, я считаю, что в C++03 , код недействителен. Однако может ли кто-нибудь объяснить, как правило изменилось в С++ 11?

(Этот вопрос был результатом предыдущий вопрос я ответил.)

  • Вы хотели сделать i двойным, а не целым? David 07.06.2012
  • @Dave: Нет, это было специально. Смотрите ссылку на предыдущий вопрос. Jesse Good 07.06.2012
  • FWIW, clang++ 3.0 не показывает предупреждение VLA. У меня нет g++, чтобы проверить это, но я полагаю, что предупреждение не исчезнет, ​​если вы измените назначение на const int i = 1;. Имеет ли это? jweyrich 07.06.2012
  • @jweyrich: компиляция с -pedantic в clang++ 3.1 дает аналогичное предупреждение. Если вы измените его на const int i = 1;, предупреждение исчезнет. Jesse Good 07.06.2012

c++constantsc++11

Ответы

Ответ 1 · рейтинг 7 · Jonathan Wakely

Связанный массив должен быть интегральным константным выражением, см. 8.3.4 [dcl.array]/1 (та же формулировка в C++03 и C++11):

Если константное выражение (5.19) присутствует, оно должно быть интегральным постоянным выражением, и его значение должно быть больше нуля.

В C++03 целочисленное константное выражение не может быть инициализировано литералом с плавающей запятой, если только оно не приведено к целочисленному типу, см. последнее предложение в 5.19 [expr.const]/1:

Интегральное выражение-константа может включать только литералы (2.13), перечислители, const переменные или статические элементы данных целочисленного или перечисляемого типов, инициализированные константными выражениями (8.5), параметры нетипового шаблона интегрального или перечисляемого типы и sizeof выражения. Плавающие литералы (2.13.3) могут появляться только в том случае, если они приведены к целочисленному типу или типу перечисления.

Это означает, что в C++03 i не является целочисленным константным выражением, поэтому его нельзя использовать в качестве связанного массива.

GCC и Clang допускают массивы переменной длины в качестве расширения C++03, поэтому он компилируется с неконстантной привязкой, но вы получаете предупреждение с -pedantic. Изменение инициализатора константы для приведения ее к целочисленному типу делает i допустимым целочисленным константным выражением:

const int i = (int) 1.0;

С этим изменением массив больше не имеет переменной длины, и нет предупреждения даже с -pedantic.

В С++ 11 5.19 [expr.const]/3 говорится:

Литеральное константное выражение - это основное константное выражение prvalue литерального типа, но не типа указателя. Интегральное константное выражение - это буквальное константное выражение интегрального типа или перечисления с незаданной областью.

Предыдущие (довольно длинные) абзацы описывают правила для основных константных выражений, но в основном в C++11 двойной инициализатор не препятствует тому, чтобы i было основным константным выражением, даже без приведения, поэтому это целочисленное константное выражение и, следовательно, действительная привязка массива, поэтому никаких предупреждений.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы