我目前正在处理SCSI参数数据块。与我的Windows PC相比,SCSI数字是big-endian。这些数字长度可以是2,3,4,6或8个字节,并存储为这些长度的BYTE
数组。
到目前为止,我使用宏从这样的数组中获取一个小端数。但是我想提出一种真正的C ++方法,所以我写了这个:
template <size_t Size>
struct ByteSwappedNumber
{
BYTE bytes[Size];
UINT64 GetValue()
{
UINT64 val = 0;
for (size_t i = 0; i < ARRAYSIZE(bytes); ++i)
{
val |= (UINT64(bytes[i]) << ((ARRAYSIZE(bytes) - i - 1) * CHAR_BIT));
}
return val;
}
};
问题是,是否可以使用模板将GetValue
的返回类型更改为可能的最小类型>= sizeof(bytes)
?
我也查看了Boost Endian库,但让它与24位数字一起工作似乎是不可能的。很高兴以其他方式展示。
答案 0 :(得分:4)
我并不确切知道你想要实现的目标,但是可以完成一些整数到返回类型的映射,例如,如下面的代码所示:
template<size_t N> struct return_type_impl : return_type_impl<N+1>
{
static_assert(N>=0 && N<=64, "N SHOULD BE POSITIVE AND SMALLER THAN 65");
};
template<> struct return_type_impl<64> { using type = std::int64_t; };
template<> struct return_type_impl<32> { using type = std::int32_t; };
template<> struct return_type_impl<16> { using type = std::int16_t; };
template<> struct return_type_impl<8> { using type = std::int8_t; };
template<size_t N>
using return_type = typename return_type_impl<N>::type;
int main()
{
static_assert(std::is_same<return_type<46>, std::int64_t>::value,"");
static_assert(std::is_same<return_type<15>, std::int16_t>::value,"");
}
它选择最近的std::intXX_t
类型,其中XX
大于整数模板参数N
。根据需要进行调整。
答案 1 :(得分:1)
我不是模板专家,但这应该可以解决问题:
using BYTE = unsigned char;
template<size_t Size>
struct type_size
{
using type = typename std::conditional
<
Size <= sizeof(uint8_t),
uint8_t,
typename std::conditional
<
Size <= sizeof(uint16_t),
uint16_t,
typename std::conditional
<
Size <= sizeof(uint32_t),
uint32_t,
uint64_t
>::type
>::type
>::type;
};
template <size_t Size>
struct ByteSwappedNumber
{
using UINTXX = typename type_size<Size>::type;
BYTE bytes[Size];
UINTXX GetValue()
{
UINTXX val = 0;
for (size_t i = 0; i < ARRAYSIZE(bytes); ++i)
{
val |= (UINTXX(bytes[i]) << ((ARRAYSIZE(bytes) - i - 1) * CHAR_BIT));
}
return val;
}
};