C++26: more constexpr in the core language
15 points by raymii
15 points by raymii
A lot of these changes are interesting because they highlight how different the constexpr environment is to the final target. This is true for pretty much any language’s constexpr equivalent.
In particular, the abstract machine treats memory as a set of objects reachable by pointers. Each pointer is, abstractly, some offset into a live object. Any pointer that isn’t an offset into an object (and derived from another pointer to the same object) is UB.
When you generate object code, you must maintain this abstraction, relocations are expressed as symbols plus offsets (some operators other than addition may also work).
When you target most architectures, you erase this abstraction and just represent pointers as integer addresses. If you want to go back from an integer to the abstract representation, that’s hard, and so constexpr
evaluation can’t do that. It has to maintain an abstract representation of pointers. This means that it’s also easy in a constexpr
context to find the underlying type of any object. Casting from a void*
to a T*
is easy in the pointers-are-integers world (it’s a no-op, it just enables different relative loads and stores in the type system) but it isn’t safe. Doing the same in constexpr
is trivial because the abstract pointer is an object (and type) ID and an offset.
Conversely, casting from a pointer to an integer is trivial in a normal target but is not easy for constexpr
because every subsequent operation on the resulting integer has to be expressed as a relocation. If you have control flow that depends on an address, that doesn’t work.
This is apparent when you try to do seemingly simple things like building a constexpr
tree. You can’t compare the address of two objects allocated in a constexpr
context and insert them into a tree depending on their relative locations. In theory, a compiler might be able to emit all of the objects in a single section to ensure that relative orderings are preserved, but you definitely can’t hash them because it can’t guarantee that they exist at specific locations.