C++20 introduced std::bit_cast for treating the same bits as if they were a different type. So, basically it does this:
template <typename T1, typename T2>
T2 undefined_bit_cast(T1 v1) {
T1 *p1 = &v1;
T2 *p2 = (T2 *)p1; // Uh oh.
T2 v2 = *p2; // Oh no! Don't do that!
return v2;
}
except without the undefined behavior that allows a compiler to replace this method with a hard drive deletion method.
I would like to use std::bit_cast, but I'm stuck using C++11. How do I correctly implement my own custom_bit_cast
, using no undefined behavior, without using the actual std::bit_cast
?
Followup question: is there a pointer bit cast? A safe way to have a T1 *
and a T2 *
pointing at the same location, and be able to read and write from both, without it being undefined behavior?
template <class T2, class T1>
T2 cpp11_bit_cast(T1 t1) {
static_assert(sizeof(T1)==sizeof(T2), "Types must match sizes");
static_assert(std::is_pod<T1>::value, "Requires POD input");
static_assert(std::is_pod<T2>::value, "Requires POD output");
T2 t2;
std::memcpy( std::addressof(t2), std::addressof(t1), sizeof(T1) );
return t2;
}
you can probably relax the pod restriction to trivially copyable.
Compilers are pretty good with the above being optimized to good assembly.
As for the pointer bit, there is no safe way to read an object of type T1
as if it was an object of type T2
where T1
and T2
are arbitrary. There are cases where it is allowed, but they are quite narrow.