CodeNebula
C++26coreexpert

constexpr Cast from void*

C++26 · The Next Frontier · Compiler flag: -std=c++26

Explanation

Allows `static_cast` from `void*` to a typed pointer in `constexpr` contexts. Previously, `void*` casts were forbidden at compile time, limiting what could be done in constant expressions involving type-erased storage.

Real-World Scenario

Implement a compile-time type-erased allocator or small buffer optimization that needs to cast between `void*` and concrete types during constant evaluation.

Quick Snippet

snippet.cpp
constexpr int test() {
    int value = 42;
    void* vp = &value;
    int* ip = static_cast<int*>(vp); // Now valid in constexpr
    return *ip;
}

static_assert(test() == 42);

Full Example

constexpr_void_cast.cpp
// CodeNebula - C++26 Example: constexpr Cast from void*
// Compile: g++ -std=c++26 -Wall -Wextra -o example constexpr_void_cast.cpp
// Note: Requires C++26 compiler support (GCC 15+ / Clang 19+ expected)

// C++26 allows static_cast from void* in constexpr contexts. Previously,
// casting from void* was forbidden at compile time, making constexpr
// memory management and type-erasure patterns impossible.

#include <iostream>
#include <type_traits>

// --- C++26 constexpr void* Cast Syntax ---
//
// constexpr int test() {
//     int x = 42;
//     void* vp = &x;                   // OK in constexpr since C++20
//     int* ip = static_cast<int*>(vp); // NEW in C++26: allowed in constexpr!
//     return *ip;
// }
//
// static_assert(test() == 42); // Passes at compile time in C++26
//
// // Enables constexpr type-erasure and allocator patterns
// constexpr auto make_and_recover() {
//     double d = 3.14;
//     void* erased = &d;
//     double* recovered = static_cast<double*>(erased);
//     return *recovered;
// }

// --- Simulation using C++20 runtime equivalents ---

// Runtime version of what C++26 allows at compile time
int runtime_void_cast_demo() {
    int x = 42;
    void* vp = &x;
    int* ip = static_cast<int*>(vp); // Fine at runtime, not constexpr pre-C++26
    return *ip;
}

double type_erasure_demo() {
    double d = 3.14;
    void* erased = &d;
    double* recovered = static_cast<double*>(erased);
    return *recovered;
}

// Simple constexpr type-erasure storage (simulated concept)
template<typename T>
struct constexpr_box {
    T value;
    constexpr const T& get() const { return value; }
    // In C++26: could store as void* and cast back in constexpr
};

int main() {
    std::cout << "=== C++26 constexpr void* Cast (Simulated) ===" << std::endl;

    std::cout << "void* -> int*:    " << runtime_void_cast_demo() << std::endl;
    std::cout << "void* -> double*: " << type_erasure_demo() << std::endl;

    constexpr constexpr_box<int> box{99};
    static_assert(box.get() == 99);
    std::cout << "constexpr_box<int>: " << box.get() << std::endl;

    // Demonstrate the pattern that C++26 enables at compile time
    int arr[] = {10, 20, 30};
    void* base = arr;
    int* typed = static_cast<int*>(base);
    std::cout << "Array via void*: " << typed[0] << ", " << typed[1]
              << ", " << typed[2] << std::endl;

    std::cout << "C++26 allows static_cast<T*>(void*) in constexpr." << std::endl;
    return 0;
}

// Expected output:
// === C++26 constexpr void* Cast (Simulated) ===
// void* -> int*:    42
// void* -> double*: 3.14
// constexpr_box<int>: 99
// Array via void*: 10, 20, 30
// C++26 allows static_cast<T*>(void*) in constexpr.
Run command
g++ -std=c++26 -Wall -Wextra -o example constexpr_void_cast.cpp