我目前正在努力刷新我的旧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);
我尝试了一些尚未定论的事情,而且由于我不是模板专家,我可能会追逐一些甚至不可行的东西......
感谢您阅读我:)
答案 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_t
到void
的类型。
或者,您可以使用模板类执行此操作:
// 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;
}