用模板化函数替换仿函数

时间:2018-06-02 12:48:21

标签: c++ templates

我目前正在努力刷新我的旧C ++项目,试图利用现代C ++带来的所有好东西。 该项目的某些部分是关于访问uint8_t数组,返回uint8_t,uint16_t或uint32_t,具体取决于所需的数据。 为了简化问题,我将抛弃任何与字节序相关的问题。

我使用仿函数访问数据,完成了以下课程:

template<std::size_t sz>
class Read
{
public:
    template <std::size_t sz>
    struct Read_traits { };

    template <>
    struct Read_traits<8> { using internal_type = std::uint8_t; };

    template <>
    struct Read_traits<16> { using internal_type = std::uint16_t; };

    template <>
    struct Read_traits<32> { using internal_type = std::uint32_t; };

    template <>
    struct Read_traits<64> { using internal_type = std::uint64_t; };

    using read_type = typename Read_traits<sz>::internal_type;

    template<typename T, ::std::size_t N>
    read_type operator()(const ::std::array<T, N> & arr, const ::std::uint32_t& adr) const {
        read_type returnValue{};
        for (uint8_t i = 0; i <= sizeof(read_type) - 1; ++i) {
            returnValue <<= 8;
            returnValue |= arr[adr + i];
        }
        return returnValue;
    };
};

用法是

int main()
{
    std::array <uint8_t, 0x4> memory {0xFE, 0xDC, 0xBA, 0x98};
    Read<32> r32;
    auto val32 = r32(memory, 0);
    std::cout << "32 bits: 0x" << std::hex << val32 << std::endl;

    return 0;
}    
  

它按照我想要的方式工作,但我想知道是否可能   创建一个常规函数来代替仿函数,仍然使用   特质?

     

IE替换2行仿函数调用:

Read<32> r;
auto val = r(memory, 0);
     

通过单行功能:

auto val Read<32>(memory, 0);

我尝试了一些尚未定论的事情,而且由于我不是模板专家,我可能会追逐一些甚至不可行的东西......

感谢您阅读我:)

2 个答案:

答案 0 :(得分:3)

你可以这样做:

// Maps 8, 16 and 32 to uint8_t, uint16_t and uint32_t, respectively
template<size_t Size>
using SizedUInt = std::conditional_t<Size == 8, uint8_t,
                   std::conditional_t<Size == 16, uint16_t,
                    std::conditional_t<Size == 32, uint32_t, void>>>;

template<size_t Size, typename T, size_t N>
SizedUInt<Size> read(const std::array<T, N>& arr, uint32_t adr)
{
    SizedUInt<Size> returnValue{};
    for (uint8_t i = 0; i <= sizeof(SizedUInt<Size>) - 1; ++i) {
        returnValue <<= 8;
        returnValue |= arr[adr + i];
    }
    return returnValue;
}

SizedUInt是一个模板别名,它使用嵌套的conditional_t模板选择正确的类型。我设置了&#34; false&#34;当模板使用的值不同于8,16或32时,为了触发编译错误,最深conditional_tvoid的类型。

或者,您可以使用模板类执行此操作:

// create a temporary of type Read<32> and call its call operator
auto val = Read<32>{}(memory, 0);

答案 1 :(得分:1)

Read作为一个类的唯一原因似乎是Read_traits的定义。但你也可以在前者之外定义后者。由于C ++丑陋而需要一些额外的typename个关键字......

请注意,首先提供sz模板参数。调用时,它是唯一显式使用的参数。扣除其余部分,与之前相同。

#include <cstdint>
#include <iostream>
#include <array>

template <std::size_t sz>
struct ReadType { };

template <>
struct ReadType <8> { using type = std::uint8_t; };

template <>
struct ReadType <16> { using type = std::uint16_t; };

template <>
struct ReadType <32> { using type = std::uint32_t; };

template <>
struct ReadType <64> { using type = std::uint64_t; };

template <std::size_t sz, typename T, ::std::size_t N>
typename ReadType<sz>::type read(const ::std::array<T, N> & arr, const ::std::uint32_t& adr) {
    using read_type = typename ReadType<sz>::type;
    read_type returnValue{};
    for (uint8_t i = 0; i <= sizeof(read_type) - 1; ++i) {
        returnValue <<= 8;
        returnValue |= arr[adr + i];
    }
    return returnValue;
};

int main()
{
    std::array <uint8_t, 0x4> memory {0xFE, 0xDC, 0xBA, 0x98};
    auto val32 = read<32>(memory, 0);
    std::cout << "32 bits: 0x" << std::hex << val32 << std::endl;

    return 0;
}