Если вы попытаетесь выполнить это в контексте постоянного выражения (т.е. когда компилятор вынужден вызывать ваш код во время компиляции, например, выражение, приводящее к размеру массива или аргументу шаблона), вы обнаружите, что он не будет компилироваться. Выполнение Constexpr требует, чтобы все, что могло бы спровоцировать UB во время компиляции, было бы неправильно сформировано А поскольку ваш код провоцирует UB (путем доступа к неактивному члену объединения), он не сможет скомпилироваться.
Все три основных компилятора потерпят неудачу на этом в контексте постоянного выражения. MSVC (на удивление) выдает самое прямое сообщение об ошибке:
(13): ошибка C2131: выражение не было константой
(9): примечание: сбой был вызван доступом к неактивному члену профсоюза
(9): примечание: см. Использование 'foo :: Foo :: integer'
Ваш код, вероятно, "работает как положено" только потому, что вы вызываете его, когда компилятору не нужно выполнять его во время компиляции. Учитывая ошибки GCC / Clang, если вы использовали его в качестве размера массива для массива в стеке, он, вероятно, вызвал расширение языка массивов переменной длины GCC / Clang. Если вы отключите это, ваш код, скорее всего, не скомпилируется. Мой пример сделал это глобальным массивом, который не допускает VLA.
Есть ли лучшее решение
Неа. Даже C ++ 20 bit_cast
не будет constexpr
, если вы указали указатель (или тип, содержащий указатели) в качестве источника или места назначения. Указатели времени компиляции - это реальные вещи, а не просто числа, представляющие адреса; преобразование их в / из целых чисел просто нецелесообразно во время компиляции.
Указатели времени компиляции должны указывать на вещи, которые существуют во время компиляции. невозможно узнать, куда они укажут время выполнения . Так что идея хеширования значения указателя во время компиляции (даже указателя на статический / глобальный объект) просто обречена с самого начала.