问题描述
我想用“通用”值映射一个键,我的意思是它可以是一个整数、浮点数、字符、字符串等等。
我特别想这样做,因为我在模型中接收了转换后的 CAN 数据,并且可能的类型是(当前)int、float 和 string。
第一个想法是创建一个可以以不同方式实现的抽象对象(每种设备类型一个),然后将其放入容器(映射或集合)中。
我认为使用“通用类型”作为值会更轻巧、更高效,这样当数据来自 CAN 总线时,容器将自动构建,而无需创建新的临时对象。
解决方法
如果您可以使用
C++17
,std::variant 是您的选择。我询问了与您的问题相关的 question。波纹管我已经提供了如何实现它的示例:
#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,0x6f,0x20,0x53,0x74,0x61,0x63,0x6b,0x4f,0x76,0x72,0x66,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,length);
std::visit([](auto&& arg)
{
std::cout << "value-1: " << arg << std::endl;
},value1);
return 0;
}
输出:
value-0: 1819043144
value-1: Hello StackOverflow!
UPD.0:我在这里没有使用 std::map
,但我认为仅使用 std::variant
作为该容器的值没什么大不了的。 >