Является ли const_cast допустимым в константном выражении? (C ++ 14, C ++ 17) - PullRequest
4 голосов
/ 01 апреля 2019

Особая проблема, с которой столкнулся пользователь, заключается в том, что существует некоторая непоследовательность в том, как компиляторы справляются с этим.

Например, этот код (https://godbolt.org/z/08Z-zi):

    constexpr auto value = 1;
    static_assert(*const_cast<int *>(&value), "value should be 1");

прекрасно компилируется с GCC, Clang и MSVC, но завершается неудачно с Intel C ++ Compiler 19.0.1 со следующей ошибкой:

error: expression must have a constant value
static_assert(*const_cast<int *>(&value), "value should be 1");

Насколько я могу судить, в стандарте прямо не указывается, что const_cast недопустимо в константном выражении. Запись через результирующий указатель будет неопределенной и поэтому недопустимой, но чтение должно быть в порядке.

Учитывая, что все основные компиляторы компилируют этот код (включая ICC <19.0.1), это может быть просто регрессия в ICC 19.0.1. </p>

1 Ответ

3 голосов
/ 01 апреля 2019

То, что может или не может появиться в константном выражении в C ++, определяется черным списком выражений или свойствами выражений. Полный список приведен в разделе [expr.const], параграф 2. В списке нет ничего, что запрещает сам const_cast. Насколько я вижу, единственный подходящий бит - это §2.7

преобразование lvalue в rvalue, если оно не применяется к

  • энергонезависимое glvalue целочисленного или перечислимого типа, которое ссылается на полный энергонезависимый объект const с предшествующим инициализация, инициализированная константным выражением, или

  • энергонезависимое glvalue, которое ссылается на подобъект строкового литерала, или

  • энергонезависимое значение, которое относится к энергонезависимому объекту, определенному с помощью constexpr, или которое относится к неизменяемому подобъекту такого объекта. объект или

  • энергонезависимое glvalue литерального типа, которое относится к энергонезависимому объекту, время жизни которого началось в пределах оценки e;

Преобразование lvalue в rvalue является стандартным для (грубо говоря) «чтения сохраненного значения объекта». Это то, что делает ваш пример. Теперь они могут вообще не появляться в константных выражениях. За исключением случаев, когда применяется одна из предыдущих пуль.

Третья пуля применяется в вашем случае. Оператор * выдает lvalue. Указанное lvalue не является энергозависимым и относится к объекту constexpr (value). Ваш код, следовательно, является допустимым C ++.

...