我正在编写一些代码来格式化十六进制数,目前它接受一个无符号的64位值。直到我意识到它格式化了一个带有太多符号扩展名的32位有符号整数,即“-1”变为“ffffffffffffffff”时,这一切都很好,很花哨。
我可以使用numeric_limits< T> :: digits:
来解决这个问题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 :(得分:2)
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
和其余整数类型添加专精。
答案 1 :(得分:0)
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);
}
(我试图将此评论发布到我的问题,但无法使多行代码正确格式化。)