Я хочу взять переменную стека и reinterpret cast
в беззнаковый целочисленный тип того же размера в байтах. Например, я мог бы взять значение double
и передать его в uint64_t
с уловкой, что биты не будут изменены. И я хочу сделать это в общем виде.
Если бы я имел дело с указателями, я использовал бы reinterpret_cast<uint64_t*>(double_ptr)
.
Я придумал решение, которое использует грязный взломать reinterpret_cast
и эффективен, но для получения довольно простого результата требуется довольно много метапрограмм.
Вопрос: есть ли лучший способ сделать это? Я уверен, что есть, и что я делаю это более сложным, чем нужно.
Я подумал об использовании шаблонного объединения типа T
и соответствующего размера int_t
, но это казалось даже хакером и, казалось, играло с поведением undefined.
edit Я понимаю, что стандарт не указывает, что double должен быть 64 бит, как указано в комментариях. Но с общим подходом я смогу получить целочисленный тип без знака того же размера, что и двойной, но большой.
#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;
}
компиляция кода выше с помощью gcc дает:
> 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