Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is reinterpret_cast not constexpr?

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?

like image 313
Conor Taylor Avatar asked Jan 25 '20 20:01

Conor Taylor


People also ask

What is the point of Reinterpret_cast?

The reinterpret_cast allows the pointer to be treated as an integral type. The result is then bit-shifted and XORed with itself to produce a unique index (unique to a high degree of probability). The index is then truncated by a standard C-style cast to the return type of the function.

Is constexpr guaranteed?

A constexpr function that is eligible to be evaluated at compile-time will only be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, compile-time evaluation is not guaranteed.

What is the point of constexpr?

constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.

Can constexpr be changed?

Both const and constexpr mean that their values can't be changed after their initialization. So for example: const int x1=10; constexpr int x2=10; x1=20; // ERROR.


1 Answers

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.

like image 132
bolov Avatar answered Oct 27 '22 18:10

bolov