Casting discipline

Code-level7 standards

Named casts, bit_cast, narrowing, punning.

Doctrine: named casts only — C-style casts are greppable nowhere and mean anything. Brace init already rejects narrowing.

auto p = static_cast<Derived*>(base);     // checked by design review
int n{3.7};                               // error: narrowing

No change; the memcpy idiom remains the only legal type-pun (reinterpret_cast + dereference is UB under aliasing rules).

float f = 1.0f;
std::uint32_t bits;
std::memcpy(&bits, &f, sizeof bits);      // the legal pun, pre-C++20

No new casts; std::byte arrives so raw memory stops being char soup, clarifying which reinterpret_casts are aliasing-legal (only to char-like types).

std::bit_cast is the constexpr-capable, UB-free pun — the memcpy idiom with a name and a type check.

auto bits = std::bit_cast<std::uint32_t>(1.0f);   // constexpr-friendly

std::to_underlying names the enum-to-integer cast; std::byteswap covers the endian flip that reinterpret hacks used to do.

std::saturate_cast clamps instead of wrapping on narrowing conversions, and constant evaluation now permits static_cast from void* — type-erased code becomes constexpr-able.

std::uint8_t level = std::saturate_cast<std::uint8_t>(big);  // clamps to 255
C++29direction · not adopted

Stable; provenance and aliasing-model clarifications (TS work) are the adjacent moving parts.

C++26 per the final working draft; C++29 rows are proposals and direction, not adopted features.