2012-04-29 2 views
22

Я пытаюсь объявить указатель constexpr инициализированному некоторой константе целое значение, но лязг в срыве все мои попытки:Constexpr значение указателя

Попытка 1:

constexpr int* x = reinterpret_cast<int*>(0xFF); 

test.cpp:1:20: note: reinterpret_cast is not allowed in a constant expression 

Попытка 2:

constexpr int* x = (int*)0xFF; 

test.cpp:1:20: note: cast which performs the conversions of a reinterpret_cast is not allowed in a constant expression 

Покушение 3:

constexpr int* x = (int*)0 + 0xFF; 

test.cpp:1:28: note: cannot perform pointer arithmetic on null pointer 

Является ли то, что я пытаюсь не допускать по дизайну? Если да, то почему? Если нет, как я могу это сделать?

Примечание: gcc принимает все эти данные.

+2

Зачем вам здесь constexpr? Не является ли constexpr эффективным тем же, что и const, если вы не используете функцию? –

+0

@RobertMason: Ну, например, если это статический член класса и он не constexpr, я не могу инициализировать его в строке. – HighCommander4

+1

Возможно, статическая встроенная функция-член будет более подходящей, чем элемент данных. –

ответ

18

Как отмечает Люк Дантон, ваши попытки блокируются правилами в [expr.const]/2, которые говорят, что различные выражения не допускаются в основной константе выражения, в том числе:

- в reinterpret_cast
- операция, которая будет иметь неопределенное поведение [Примечание: в том числе [...] некий указатель арифметической [...] - конец записки]

первая пуля исключает ваш первый пример. Второй пример исключается первой пули выше, плюс правило из [expr.cast]/4, что:

Преобразования выполняются [...] reinterpret_cast [...] может быть выполнена используя буквенное обозначение преобразования явного типа. Используются те же смысловые ограничения и поведение.

Вторая пуля была добавлена ​​WG21 core issue 1313, и уточняет, что арифметические операции над указателями на нулевой указатель не допускается в постоянном выражении. Это исключает ваш третий пример.

Даже если эти ограничения не относятся к основным константных выражений, он все равно будет невозможно инициализировать constexpr указатель со значением полученного литьем целое, так как переменная указатель constexpr должен быть инициализируется константным выражением адреса, который, [expr.const]/3, должно быть оценено в

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

Целое число, отличное от типа указателя, не является ничем из этого.

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

Если ваша цель - объявить переменную, для которой выполняется статическая инициализация, вы можете просто отказаться от constexpr - и clang, и g ++ выдадут статический инициализатор для этого выражения. Если вам нужно это выражение быть частью константного выражения для какой-то причины, у вас есть два варианта:

  • реструктурировать свой код так, что intptr_t передается вокруг вместо указателя, и привести его к типу указателя, когда вы необходимо (за пределами постоянного выражения) или
  • Использовать __builtin_constant_p((int*)0xFF) ? (int*)0xFF : (int*)0xFF. Эта точная форма выражения (с __builtin_constant_p в левой части условного оператора) отключает проверку строгого постоянного выражения в объятиях условного оператора и мало известна, но documented, не переносимое расширение GNU, поддерживаемое и gcc и clang.
4

Причина в том, что сообщение об ошибке (за один раз, очень полезно): reinterpret_cast не допускается в постоянном выражении. Он указан как одно из явных исключений в 5.19 (параграф 2).

Изменение reinterpret_cast в литье C-стиля все равно заканчивается семантическим эквивалентом reinterpret_cast, так что это не помогает (и снова сообщение очень явное).

Если у вас есть способ получить указатель со значением 0, вы действительно можете использовать p + 0xff, но я не могу придумать способ получения такого указателя с постоянным выражением. Вы могли бы полагаться на значение нулевого указателя (0 в контексте указателя, как и вы, или nullptr), имеющее значение 0, но, как вы видели, ваша реализация отказывается это делать. Я думаю, что это разрешено. (Например, реализациям разрешено вызывать большинство константных выражений.)

+1

, и он должен быть '0xff/sizeof (* x)', который он добавляет. –

Смежные вопросы