Работая во встроенной среде, я неоднократно пишу код, который берет массив байтов из уровня протокола и превращает эти байты в представление класса C ++.
Пример массива байтов, который представляет uint32_t
, за которым следует uint8_t
, а затем uint16_t
, может выглядеть следующим образом.
std::array<uint8_t, 7> bytes(0x01, 0x02, 0x03, 0x04, 0x10, 0x20, 0x30);
Где 0x01020304
- мой uin32_t
, 0x10
- мой uint8_t
, а 0x2030
- мой uint16_t
.
У меня также есть переменная функция func()
, которую я хочу вызвать со значениями, проанализированными из полезной нагрузки.
Для этого я вручную определяю промежуточный объект:
// Declaring the Object
struct MY_TYPE
{
uint32_t val1;
uint8_t val2;
uint16_t val3;
} __attribute__((__packed__));
// Processing the Bytes
auto & object(reinterpret_cast<MY_TYPE *>(&bytes));
func(object.val1, object.val2, object.val3)
То, что я хочу сделать, - это реализовать класс переменных, чтобы мне не нужно было повторно реализовывать MY_TYPE
для каждой комбинации типов.
Вот что я изначально попробовал:
template <typename... Types>
struct GENERIC_CLASS
{
template <typename ReturnType, std::size_t ArraySize>
ReturnType getValueFromArray(std::array<uint8_t, ArraySize> const & array,
uint32_t & index);
// Note, not valid c++ since the size of the array (N) isn't
// specified. This has been omitted for simplicity.
void process(std::array<uin8_t, N> const & array)
{
auto currentIndex(u0);
// Assumes this class has a specialization
// for getValueFromArray for all of the types in Types.
// This code doesn't work because there is no sequence point
// between each call to getValueFromArray, so the
// currentIndex can be incremented in a non-deterministic way.
func(this->getValueFromArray<Types>(array, currentIndex)...);
}
};
Мне удалось обойти эту проблему, введя новый класс:
template <typename T, std::size_t position>
struct Param
{
using type = T;
static constexpr std::size_t offset = position;
};
Таким образом, вместо сохранения currentIndex
во время выполнения, я могу указать смещение каждого аргумента в коде, например:
GENERIC_CLASS<Param<uint32_t, 0>, Param<uint8_t, 4>, Param<uint16_t, 5>>
Вышеуказанное может привести к ошибкам, так как смещения могут быть неправильными. Есть ли какой-нибудь способ для генерации моей последовательности Params
из набора типов параметров путем накопления размеров?
В качестве альтернативы, есть ли обходной путь для проблемы точки последовательности, о которой я упоминал выше?