Объектная модель C ++ обычно является фикцией, соглашением между программистом, пишущим код, и компилятором, генерирующим исполняемый двоичный файл. Для исполняемого файла объекты не существуют; это просто биты, хранящиеся в памяти. Таким образом, вы можете использовать тот факт, что в C ++ есть десятки лазеек, которые можно использовать, чтобы эффективно притвориться, что объектная модель нереальна. Многие из них демонстрируют неопределенное поведение, но ни один компилятор не будет проверять эти нарушения объектной модели и останавливать вас. Вы нарушили свой конец контракта, но компилятор не обратил на это внимания, поэтому вам это сойдет с рук.
Это не так при вычислении константных выражений. Скомпилированный исполняемый файл запускается на CPU; оценка константного выражения выполняется внутри компилятора. Объектная модель не должна отображать «биты», «память» или что-то подобное; это может быть реальная объектная модель с полным отслеживанием и анализом времени жизни.
Стандарт C ++ поэтому требует, чтобы во время постоянной оценки, если вы делаете что-нибудь , которое демонстрирует UB, компилятор должен это обнаружить и объявите вашу программу плохо сформированной. Кроме того, для кода constexpr категорически запрещено использовать самый большой бэкдор из всех: reinterpret_cast
.
Во время компиляции объекты не хранятся в байтах. Таким образом, вы не можете обращаться с ними, как если бы они были.
Это особенно важно, потому что среда выполнения компилятора и среда выполнения возможного двоичного файла не обязательно должны быть одинаковыми . Если вы разрабатываете какую-либо встроенную систему, порядок байтов ЦП, на который вы нацеливаетесь, может не совпадать с порядком байтов ЦП, на котором выполняется компилятор . Поэтому, если бы вы могли получить доступ к любым данным времени компиляции как к байтам, вы бы получили другой ответ во время компиляции, чем во время выполнения.
Это плохо.
C + +20 std::bit_cast
существует и может помочь, но даже это не все. Тип подходит только для constexpr
bit_cast
-ing, если это TriviallyCopyable и не хранит указатели (помимо прочего). Это потому, что указатели времени компиляции - это не просто адреса; это сложный тип данных, который должен запоминать, на какой объект он указывает (иначе было бы невозможно обнаружить, когда вы static_cast
пытаетесь получить доступ к объекту через неправильный тип).
Но если вы ограничите свои типы теми, которые constexpr
bit_cast
способны, то вы можете bit_cast
их массивом их размера.
Обратите внимание, что constexpr
bit_cast
- это не самая простая вещь для реализации именно потому, что она должна заставить данные исходного объекта работать так, как если бы они выполнялись на целевом процессоре и среде, а не в той, в которой выполняется компилятор. Таким образом, если целью является машина с прямым порядком байтов, а источник - с прямым порядком байтов, constexpr
bit_cast
должен выполнить преобразование с прямым порядком байтов, и оно должно выполнять такое преобразование с указанием c знания того, что каждый компонентный тип исходного и целевого объектов.