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?
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);
}