一种单一的数据结构,用于从脚本中读取任意类型的变量,以便在运行时进行检索和编辑

A single data structure for reading in arbitrary type variables from a script, for retrieval and editing at runtime

本文关键字:变量 类型 编辑 运行时 检索 任意 一种 单一 数据结构 脚本 用于      更新时间:2023-10-16

我想为一些机器人软件存储任意参数数据。我将举一些例子来澄清我想做什么:

例如,我想存储变量"quadruped.gait.step_height=0.25"answers"quadrupped.gait_type="trot",这应该分解为类似的内容

variable_map["quadruped"]["gait"]["step_height"] = 0.25;

variable_map["quadruped"]["gait"]["gait_type"] = "trot";

我目前必须处理这种事情的代码(如果我知道变量的类型,它就可以正常工作):

std::map<std::string, void* > var_map;
template <class X>
void set_variable(std::string key, X var)
{
   var_map[key] = &var;
}
template <class X>
X get_variable(std::string key)
{
   return *reinterpret_cast<X*>(var_map[key]);
}

这就完成了将每个变量存储在中的看起来不那么干净的任务

variable_map["quadruped.gait.step_height"] = 0.25;

这感觉像是一种粗制滥造的方式来做我想做的事。我需要提前知道变量的类型:

set_variable<bool>("quadruped.PID.workspace.active",true);
bool workspace_active = get_variable<bool>("quadruped.PID.workspace.active");

理想情况下,我希望在启动时在XML读取器或某种脚本解析格式中处理这种类型的变量分配。

我觉得这是软件开发人员的共同需求,我忍不住觉得我正在重新发明解决这个问题的方法。有没有一段开源代码(最好有一个好的许可证),或者只是一种更简单的脚本阅读方式:

quadruped.gait.gait_timing = [ 0 0.5 0 0.5 ]
quadruped.gait.step_height = 0.25
quadruped.gait.gait_type = "trot"
quadruped.PID.workspace.active = 1

并将其存储为:

variable_map["quadruped"]["gait"]["gait_timing"] = (std::vector) % containing [ 0 0.5 0 0.5 ]
variable_map["quadruped"]["gait"]["step_height"] = (double) 0.25;
variable_map["quadruped"]["gait"]["gait_type"] = (std::string) "trot";
variable_map["quadruped"]["PID"]["workspace"]["active"] = (int) 1;

或者可能只是以任何方式存储它们,我可以在代码中按名称检索它们,比如在我之前的例子中:

bool workspace_active = get_variable<bool>("quadruped.PID.workspace.active");

谢谢你的帮助。如果你需要进一步澄清我提出的任何一点,我将密切关注这个问题。

您的问题确实是一个常见问题。因此,存在一种常见的解决方案,即存储任意类型的变量的boost::variant

优点是它基于您考虑的所有潜在类型构建变体类型(并作为模板参数提供):

typedef boost::variant< int, std::string, double> vtype;  

这种方法可以避免常见的问题,比如令人讨厌的未对齐变量(例如参见这个SO问题)。它还启用了一些编译时类型检查,确保您不会意外使用未预见的类型。

vtype v1, v2; 
v1 = "Hello"; 
v2 = 0.25; 
cout << v1 << v2;  

如果你知道存储在一个对象中的类型,你可以很容易地得到它:而不是像*reinterpret_cast<X*>那样危险:boost::get<X>()

boost提供了一种访问机制,以优雅的方式提供足够的类型相关代码,用于处理变体对象。你会在这个答案开头的链接中找到一些不错的例子。

考虑使用Boost.PropertyTree,它实现了"层次"映射,还通过解析器从一些常见格式的文件中读取配置。默认情况下,它以std::string格式存储值,但使用boost::lexical_cast来支持设置和获取其他类型的值。如果您愿意,您可以使用Boost.Any或Boost.Variant来存储值,但这将失去一些解析功能。