Working in an embedded environment, I'm repeatedly writing code that takes an array of bytes from a protocol layer and turns those bytes into a C++ class representation.
An example array of bytes that represents a uint32_t
, followed by a uint8_t
, followed by a uint16_t
might look like this.
std::array<uint8_t, 7> bytes(0x01, 0x02, 0x03, 0x04, 0x10, 0x20, 0x30);
Where 0x01020304
is my uin32_t
, 0x04
is my uint8_t
and 0x2030
is my uint16_t
.
I also have a variadic function func
that I want to call with the values parsed out of the payload.
To achieve this, I manually define an intermediate object:
// 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)
What I want to do is implement a variadic class such that I don't need to re-implement MY_TYPE
for every combination of types.
Here's what I initially tried:
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)...);
}
};
I was able to work around this problem by introducing a new class:
template <typename T, std::size_t position>
struct Param
{
using type = T;
static constexpr std::size_t offset = position;
};
This way, instead of maintaining currentIndex
at runtime, I can specify the offset of each argument in code, like this:
GENERIC_CLASS<Param<uint32_t, 0>, Param<uint8_t, 4>, Param<uint16_t, 5>>
The above is potentially error prone, as the offsets could be wrong. Is there some way to generate my sequence of Params
from a parameter pack of types by accumulating sizes?
Alternatively, is there some workaround for the sequence point problem that I've mentioned above?
Aucun commentaire:
Enregistrer un commentaire