X1ngChui
X1ngChui

Reputation: 95

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?

Upvotes: 2

Views: 119

Answers (1)

wohlstad
wohlstad

Reputation: 29009

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

Upvotes: 5

Related Questions