Самый короткий / самый чистый способ превратить целое число неизвестного размера в его беззнаковую форму?

Я пишу некоторый код для форматирования шестнадцатеричного числа, и в настоящее время он принимает 64-разрядное значение без знака. Это было все прекрасно, пока я не понял, что он форматирует 32-разрядное целое число со знаком со слишком большим расширением знака, то есть «-1» становится «ffffffffffffffff».

Я мог бы решить это с помощью numeric_limits<T> :: цифры:

template<class Int>
void Format(Int v) {
switch(std::numeric_limits<Int>::digits) {
case 7:
case 8:
CallFormatRoutine(0xFF & v);
break;
case 15:
case 16:
CallFormatRoutine(0xFFFF & v);
break;
case 31:
case 32:
CallFormatRoutine(0xFFFFFFFF & v);
break;
case 63:
case 64:
CallFormatRoutine(v);
break;
}
}

Но мне было интересно, есть ли какой-нибудь лучший (более короткий) путь. В частности, лучший способ, который работает с C ++ 03 и C ++ 11. В идеале должна быть какая-то подпрограмма, которая будет возвращать беззнаковую версию любого целого числа, которое вы ей дадите, но я не смог найти это в стандарте. Если бы я мог использовать C ++ 11, я мог бы написать это, хотя, возможно, с приведением, чтобы избежать предупреждения о преобразовании со знаком / без знака:

template<class Int>
void Format(Int v) {
std::make_unsigned<Int>::type unsigned_v = v;
CallFormatRoutine(unsigned_v);
}

Есть ли что-нибудь хорошее и короткое, чтобы сделать это, что также работает с C ++ 03?

0

Решение

std::make_unsigned это самый хороший и самый короткий способ выполнить то, что вы хотите, но у вас есть некоторые ошибки в вашем примере. Это должно выглядеть примерно так:

template<class Int>
Format(Int v) {
auto unsigned_v = static_cast<typename std::make_unsigned<Int>::type>(v);
CallFormatRoutine(unsigned_v);
}

А с помощью компилятора C ++ 14 соответствующая строка может быть сокращена до

auto unsigned_v = static_cast<std::make_unsigned_t<Int>>(v);

Для компиляторов C ++ 03 есть boost::make_unsigned, или вы могли бы реализовать это самостоятельно, но это немного утомительно, потому что вам нужно обрабатывать все встроенные типы.

template<typename T>
struct make_unsigned
{ typedef T type; };

template<>
struct make_unsigned<char>
{ typedef unsigned char type; };

template<>
struct make_unsigned<signed char>
{ typedef unsigned char type; };

Аналогично, добавьте специализации для short, int и остальные целочисленные типы.

2

Другие решения

FWIW, я закончил с использованием sizeof вместо std :: numeric_limits и использованием static_cast вместо 0xFFFFFFFF:

template<class Int>
void Format(Int v) {
static_assert(sizeof(v) == 1 || sizeof(v) == 2 || sizeof(v) == 4 || sizeof(v) == 8,
"Unknown integer type");
CallFormatRoutine( sizeof(v) == 1 ? static_cast<uint8>(v)
: sizeof(v) == 2 ? static_cast<uint16>(v)
: sizeof(v) == 4 ? static_cast<uint32>(v)
: static_cast<uint64>(v);
}

(Я пытался опубликовать комментарий к моему вопросу, но не смог получить многострочный код для правильного форматирования.)

0

По вопросам рекламы [email protected]