I want to take a stack variable and reinterpret cast
it into an unsigned integer type of the same size in bytes. For example, I might want to take double
value and cast it to an uint64_t
, with the catch that the bits are not modified. And I want to do it in a generic fashion.
If I was dealing with pointers, I would use a reinterpret_cast<uint64_t*>(double_ptr)
.
I have come up with a solution, which uses a dirty hack on reinterpret_cast
, and is effective, but it requires quite a lot of meta-programming to get a fairly simple outcome.
The question: is there a better way to do this? I am sure that there is, and that I am making this more complicated than need be.
I did think about using a templated union of type T
and appropriately sized int_t
, but that seemed even hackier, and seemed to play with undefined behavior.
edit I understand that the standard doesn't specify that double should be 64 bits, as pointed out in the comments. But with a generic approach, I will be able to get an unsigned integral type the same size as double, however big that is.
#include <iostream>
template <typename T, std::size_t S>
struct helper {};
template <typename T>
struct helper<T, 1> {
using type = uint8_t;
};
template <typename T>
struct helper<T, 2> {
using type = uint16_t;
};
template <typename T>
struct helper<T, 4> {
using type = uint32_t;
};
template <typename T>
struct helper<T, 8> {
using type = uint64_t;
};
template <typename T>
using int_type = typename helper<T, sizeof(T)>::type;
template <typename T>
int_type<T> caster(T value) {
int_type<T> v;
*reinterpret_cast<T*>(&v) = value;
return v;
}
int main(void) {
{
auto val = caster(0.);
static_assert(std::is_same<uint64_t, decltype(val)>::value, "no good");
std::cout << sizeof(val)*8 << " " << val << std::endl;
}
{
auto val = caster(0.f);
static_assert(std::is_same<uint32_t, decltype(val)>::value, "no good");
std::cout << sizeof(val)*8 << " " << val << std::endl;
}
{
auto val = caster(-0.);
static_assert(std::is_same<uint64_t, decltype(val)>::value, "no good");
std::cout << sizeof(val)*8 << " " << val << std::endl;
}
{
auto val = caster(-0.f);
static_assert(std::is_same<uint32_t, decltype(val)>::value, "no good");
std::cout << sizeof(val)*8 << " " << val << std::endl;
}
return 0;
}
compiling the code above with gcc gives:
> g++ --version
g++ (GCC) 4.8.2 20131016 (Cray Inc.)
> g++ -std=c++11 test.cpp && ./a.out
64 0
32 0
64 9223372036854775808
32 2147483648
See Question&Answers more detail:os