In the following question:
What's a proper way of type-punning a float to an int and vice-versa?, the conclusion is that the way to construct doubles from integer bits and vise versa is via memcpy
.
That's fine, and the pseudo_cast
conversion method found there is:
template <typename T, typename U>
inline T pseudo_cast(const U &x)
{
static_assert(sizeof(T) == sizeof(U));
T to;
std::memcpy(&to, &x, sizeof(T));
return to;
}
and I would use it like this:
int main(){
static_assert(std::numeric_limits<double>::is_iec559);
static_assert(sizeof(double)==sizeof(std::uint64_t));
std::uint64_t someMem = 4614253070214989087ULL;
std::cout << pseudo_cast<double>(someMem) << std::endl; // 3.14
}
My interpretation from just reading the standard and cppreference is/was that is should also be possible to use memmove
to change the effective type in-place, like this:
template <typename T, typename U>
inline T& pseudo_cast_inplace(U& x)
{
static_assert(sizeof(T) == sizeof(U));
T* toP = reinterpret_cast<T*>(&x);
std::memmove(toP, &x, sizeof(T));
return *toP;
}
template <typename T, typename U>
inline T pseudo_cast2(U& x)
{
return pseudo_cast_inplace<T>(x); // return by value
}
The reinterpret cast in itself is legal for any pointer (as long as cv is not violated, item 5 at cppreference/reinterpret_cast). Dereferencing however requires memcpy
or memmove
(§6.9.2), and T and U must be trivially copyable.
Is this legal? It compiles and does the right thing with gcc and clang.
memmove
source and destinations are explicitly allowed to overlap, according
to cppreference std::memmove and memmove,
The objects may overlap: copying takes place as if the characters were copied to a temporary character array and then the characters were copied from the array to dest.
Edit: originally the question had a trivial error (causing segfault) spotted by @hvd. Thank you! The question remains the same, is this legal?