std::variant is your option if you can use C++17
. I asked the question that is related to your problem. Bellow I've provided the example of how it can be implemented:
#include <iostream>
#include <variant>
#include <assert.h>
#include <string_view>
#include <unordered_map>
enum class ValueType : uint8_t
{
Undefined = 0x00,
Uint16,
Uint32,
AsciiString,
};
typedef uint64_t FieldId;
struct FieldInfo
{
std::string _name;
ValueType _type;
uint8_t size; // in bytes
};
typedef std::unordered_map<FieldId, FieldInfo> FieldContainer;
static FieldContainer requestFields =
{
{ 0, { "user-id", ValueType::Uint32, sizeof (uint32_t) } },
{ 1, { "group-id", ValueType::Uint16, sizeof (uint16_t)} },
{ 2, { "user-name", ValueType::AsciiString, 0} },
};
std::variant<uint8_t, uint32_t, std::string_view> getValue(ValueType type,
const uint8_t* data,
size_t length)
{
if (type == ValueType::Uint32)
{
assert(length == sizeof(uint32_t));
return *reinterpret_cast<const uint32_t*>(data);
}
if (type == ValueType::Uint16)
{
assert(length == sizeof(uint16_t));
return *reinterpret_cast<const uint16_t*>(data);
}
else if (type == ValueType::AsciiString)
{
return std::string_view(reinterpret_cast<const char*>(data), length);
}
return static_cast<uint8_t>(0);
}
int main(int argc, char *argv[])
{
const uint8_t arr[] = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x4f, 0x76, 0x65, 0x72, 0x66, 0x6c, 0x6f, 0x77, 0x21};
size_t length = sizeof(arr);
const auto value0 = getValue(requestFields[0]._type, arr, requestFields[0].size);
std::visit([](auto&& arg)
{
std::cout << "value-0: " << arg << std::endl;
}, value0);
const auto value1 = getValue(requestFields[2]._type, arr, length);
std::visit([](auto&& arg)
{
std::cout << "value-1: " << arg << std::endl;
}, value1);
return 0;
}
Output:
value-0: 1819043144
value-1: Hello StackOverflow!
UPD.0: I didn't use std::map
here, but I think it is not big deal just to use std::variant
as value of that container.