Почему reinterpret_cast не является constexpr? - PullRequest
7 голосов
/ 25 января 2020

Рассмотрим следующий фрагмент:

static constexpr uint8_t a = 0;
static constexpr const int8_t *b = reinterpret_cast<const int8_t *>(&a);

Не удается скомпилировать с error: a reinterpret_cast is not a constant expression, потому что стандарт C ++ запрещает , используя reinterpret_cast в constexpr.

Однако компиляция завершается успешно, если я хочу сохранить значение b в PROGMEM (для микроконтроллеров AVR):

static constexpr uint8_t a = 0;
static const int8_t PROGMEM *const b = reinterpret_cast<const int8_t *>(&a);

В этом случае компилятор может доказать, что выражение reinterpret_cast<const int8_t *>(&a) является константой времени компиляции, поскольку она вставляет свой результат (адрес, указывающий на некоторый байт, содержащий ноль) в программном пространстве в двоичном файле:

_ZL1g:
  .zero   1
  .section        .progmem.data,"a",@progbits
  .type   _ZL1b, @object
  .size   _ZL1b, 2
_ZL1b:
  .word   _ZL1g

Кроме того, я понимаю, что reinterpret_cast директива времени компиляции Так почему же его нельзя использовать внутри constexpr?

Ответы [ 2 ]

5 голосов
/ 26 января 2020

Во время выполнения язык C ++ имеет концепцию неопределенного поведения. При определенных (хорошо определенных) условиях программа имеет неопределенное поведение, что означает, что она может проявлять любое поведение: она может взломать sh, она может зависнуть навсегда, она может напечатать gibberi sh, она может работать или это может сделать что угодно. Упрощенное объяснение того, почему это существует, - это производительность.

Во время выполнения это компромисс (если хотите, компромисс), но он недопустим во время компиляции. Если бы стандарт позволял UB во время компиляции, не только было бы законно получать сбои при компиляции программы или до бесконечности компиляции, но вы никогда не могли быть уверены в достоверности скомпилированного исполняемого файла.

Как таковой любая форма constexpr должна быть на 100% свободна от неопределенного поведения. Никаких исключений по этому поводу. Никакой задержки.

Один печально известный источник UB - reinterpret_cast. Есть только несколько действительных вариантов использования reinterpret_cast, большинство из которых приводит к UB. Кроме того, практически невозможно проверить, действительно ли использование. Так что reinterpret_cast не допускается во время компиляции, т.е. это не разрешено в constexpr.

0 голосов
/ 26 января 2020

Так почему же его нельзя использовать внутри constexpr?

Просто потому, что стандарт этого не позволяет. constexpr - это функция, которая с C ++ 11 постоянно расширяется по различным стандартам, поэтому естественно подумать, что подмножество reinterpret_cast использований может работать.

Вопрос в том, можно ли разрешить это было бы на самом деле полезно или активно вредно. reinterpret_cast очень мало хороших применений, особенно если вы программируете и компилируете свой код, предполагая, что действует строгое правило псевдонимов: было бы легко создавать указатели, нарушающие его.

С другой стороны, это Ясно, что для встраиваемых пользователей и специализированных компиляторов / флагов / сред это может быть полезно в некоторой степени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...