问题
Consider the following snippet:
static constexpr uint8_t a = 0;
static constexpr const int8_t *b = reinterpret_cast<const int8_t *>(&a);
This fails to compile with error: a reinterpret_cast is not a constant expression
, because the C++ standard forbids using reinterpret_cast
in constexpr
.
However compilation succeeds if I want to store the value b in PROGMEM (for AVR microcontrollers):
static constexpr uint8_t a = 0;
static const int8_t PROGMEM *const b = reinterpret_cast<const int8_t *>(&a);
In this case the compiler is able to prove that the expression reinterpret_cast<const int8_t *>(&a)
is compile-time constant, since it inserts its result (an address pointing to some byte containing a zero) into program space in the binary:
_ZL1g:
.zero 1
.section .progmem.data,"a",@progbits
.type _ZL1b, @object
.size _ZL1b, 2
_ZL1b:
.word _ZL1g
Also, my understanding is that reinterpret_cast
is a compile-time directive. So how come it can't be used inside a constexpr
?
回答1:
At runtime the C++ language has the concept of Undefined Behavior. Under certain (well specified) conditions, the program has Undefined Behavior, that means that it can exhibit any behavior: it can crash, it can hang forever, it can print gibberish, it can appear to work, or it can do anything. A simplified explanation of why this exists is performance.
At runtime this is a tradeoff (a compromise if you will), but it is unacceptable at compile time. If the standard would allow UB at compile time, not only it would be legal to get crashes while compiling the program or compile ad infinitum, but you could never be sure of the validity of the compiled executable.
As such, any form of constexpr
would have to be 100% free of Undefined Behavior. No exceptions about it. No leeway.
One notorious source of UB is reinterpret_cast
. There are very few valid uses of reinterpret_cast
, most of them result in UB. Plus it is practically impossible to check if the use is valid. So reinterpret_cast
is not allowed during compilation, i.e. it is not allowed in constexpr.
回答2:
So how come it can't be used inside a constexpr?
Simply because the standard does not allow it. constexpr
has been a feature that has been ever expanding since C++11 over the different standards, so it is natural to think that a subset of reinterpret_cast
uses could work.
The question is whether allowing it would be actually useful or actively harmful. There are very few good uses of reinterpret_cast
, specially if you program and compile your code assuming the strict aliasing rule holds: it would be easy to create pointers that break it.
On the other hand, it is clear that, for embedded users and specialized compilers/flags/environments, it could be useful to some degree.
来源:https://stackoverflow.com/questions/59913275/why-is-reinterpret-cast-not-constexpr