I am trying to convert a long list of key and value pairs into a map so that I can just iterate over it instead of defining each of them line-by-line, but I have a mix of data types for the values (uint8_t, uint16_t, uint32_t, and uint64_t).
Here's a sample of the data I am trying to build a mapping of:
static constexpr uint8_t data1{0x01};
static constexpr uint16_t data2{0x0002};
static constexpr uint32_t data3{0x00000003};
static constexpr uint64_t data4{0x0000000000000004};
I tried doing a union and a struct:
union/struct dtypes {
uint8_t i;
uint16_t j;
uint32_t k;
uint64_t l;
};
then here's my attempt at creating the map:
std::map<std::string, dtypes> mymap = {{"data1", 0x01},
{"data2", 0x0002},
{"data3", 0x00000003},
{"data4", 0x0000000000000004}};
then I try to do a for loop to populate a vector of uint8_t's (call it vec):
for (auto iter = mymap.begin(); iter != mymap.end(); iter) {
byte_pushback(vec, iter->second)
};
but the error message I am getting is:
error: could not convert "'{{"data1", 0}, {"data2", 2}, and so on..' from '<brace-enclosed initializer list>' to 'std::map<std::__cxx11::basis_string<char>, dtypes>'
{"data4", 0x0000000000000004}};
^
|
<brace-enclosed initializer list>
has anyone ever tried doing something like this? is it even worth it to attempt this? Thanks in advanced!
p.s. this byte_pushback() function breaks the uint16_t, uint32_t, uint64_t into a bunch of uint8_ts and does a push back, so data2 would be {0x00, 0x02}
CodePudding user response:
How I would do it would look something like this:
struct MyUnion {
int type;
uint8_t m8;
uint16_t m16;
uint32_t m32;
uint64_t m64;
};
class MyMap {
public:
void push(std::string key, uint8_t m8);
void push(std::string key, uint16_t m16);
void push(std::string key, uint32_t m32);
void push(std::string key, uint64_t m64);
bool has_key(std::string key) const;
bool is_8(std::string key) const;
bool is_16(std::string key) const;
bool is_32(std::string key) const;
bool is_64(std::string key) const;
uint8_t get_8(std::string key) const;
uint16_t get_16(std::string key) const;
uint32_t get_32(std::string key) const;
uint64_t get_64(std::string key) const;
private:
mutable std::map<std::string, MyUnion> mapimpl;
};
The implementations will look something like this:
void MyMap::push(std::string key, uint8_t m8) {
MyUnion u; u.type=0; u.m8 = m8;
mapimpl[key]=u;
}
bool MyMap::is_8(std::string key) const
{
return mapimpl[key].type==0;
}
uint8_t MyMap::get_8(std::string key) const
{
return mapimpl[key].m8;
}
And the remaining function has_key():
bool MyMap::has_key(std::string key) const
{
return mapimpl.find(key)!=mapimpl.end();
}
Then populating the map will look something like this:
MyMap m;
m.push("key1",(uint8_t)0xff);
m.push("key2",(uint16_t)0xffff);
CodePudding user response:
You need to change the question so that it clearly represent your problem.
To the point, you should initialize the map like this.
std::map<std::string, dtypes> mymap = {
{"data1", {.i = 0x01}},
{"data2", {.j = 0x0002}},
{"data3", {.k = 0x00000003}},
{"data4", {.l = 0x0000000000000004}},
};
Using an union or struct with properly named members helps to simplify implementations of encoding and decoding fields and is good for the readability.