根据模板参数大小在成员函数中使用不同的返回类型

时间:2016-02-11 21:11:24

标签: c++ templates visual-c++ endianness

我目前正在处理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位数字一起工作似乎是不可能的。很高兴以其他方式展示。

2 个答案:

答案 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,"");
}

Demo on Coliru

它选择最近的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;
    }
};