Ответ 1
Как отмечает Люк Дантон, ваши попытки блокируются правилами в [expr.const]/2, которые говорят, что в выражении core constant не допускаются различные выражения, включая:
- a
reinterpret_cast
- операция, которая имела бы поведение undefined [Примечание: включая [...] определенную арифметику указателя [...] - примечание конца]
Первая пуля исключает ваш первый пример. Второй пример исключается первой маркой выше, плюс правило из [expr.cast]/4, что:
Преобразования, выполненные с помощью [...] a
reinterpret_cast
[...], могут быть выполнены с использованием литой нотации преобразования явного типа. Используются те же смысловые ограничения и поведение.
Вторая пуля была добавлена основной проблемой 1321 в WG21 и поясняет, что арифметика указателя на нулевом указателе недопустима в постоянном выражении. Это исключает ваш третий пример.
Даже если эти ограничения не применимы к основным константным выражениям, было бы невозможно инициализировать указатель 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.