c++templatesconstexprcompile-timereinterpret-cast

How to reinterpret a value as bytes in a compile-time context in C++


I'm trying to implement a hash function that can be used at compile-time. To achieve this, I need to reinterpret a value (e.g., an int or a float) as its raw bytes.
However, when using compile-time evaluation, pointer type punning (reinterpretation) is not allowed due to strict aliasing and other restrictions.

Here's a simplified example to illustrate the issue:

template <typename T>
constexpr size_t hash(const T& value) {
    const unsigned char* byte_ptr = reinterpret_cast<const unsigned char*>(&value); // NOT allowed.

    size_t hash = 0;
    for (size_t i = 0; i < sizeof(T); ++i) {
        hash ^= byte_ptr[i];
    }
    return hash;
}

Is there a standard-compliant way to reinterpret a value as bytes in a constexpr context?


Solution

  • std::bit_cast (available since C++20) supports constexpr.
    You can bit_cast to std::array and then use std::array::operator[] (which supports constexpr as well) to access the bytes:

    #include <array>
    #include <cstddef>
    #include <bit>
    
    template <typename T>
    constexpr size_t byte_sum(const T& value) {
        //const unsigned char* byte_ptr = reinterpret_cast<const unsigned char*>(&value); // NOT allowed.
        auto arr = std::bit_cast<std::array<unsigned char, sizeof(value)>>(value);
        size_t hash = 0;
        for (size_t i = 0; i < sizeof(T); ++i) {
            hash ^= arr[i];
        }
        return hash;
    }
    
    int main() {
        constexpr double d = 5;
        [[maybe_unused]] constexpr size_t h = byte_sum(d);
    }
    

    Live demo