yaml-cpp解析含复杂键YAML文件失败及lib-yaml复杂键支持性问询
yaml-cpp解析含复杂键YAML文件失败及lib-yaml复杂键支持性问询
首先明确一点:YAML 规范本身是支持你示例里这种复杂映射键的,而且lib-yaml(yaml-cpp底层依赖的解析库)本身也能处理这种结构——它负责YAML的语法解析并生成事件流,对复杂键的语法是完全兼容的。问题其实出在yaml-cpp的高层API处理上,默认情况下它对复杂键的支持有限。
先看你给出的YAML示例:
thr: - ? {cpu: 1, mem: 1} : 24 - ? {cpu: 2, mem: 2} : 42
这个结构里,thr是一个数组,每个数组元素是一个以映射(字典)作为键的单键值对映射,这种写法完全符合YAML规范,但yaml-cpp默认不会自动识别这种键类型,所以才会抛出解析异常。
这里给你两种解决思路:
思路一:调整YAML结构(最简单)
如果业务场景允许,把复杂键拆成嵌套结构,避免直接用映射当键,yaml-cpp可以直接解析:
thr: - cpu: 1 mem: 1 value: 24 - cpu: 2 mem: 2 value: 42
这种结构在代码里也更容易访问,直接通过config["thr"][0]["cpu"]就能拿到对应的值,不需要额外处理。
思路二:自定义类型解析(保留原结构)
如果必须保留原有的复杂键结构,你需要给yaml-cpp定义一个自定义类型的转换规则,让它知道如何解析作为键的映射。
比如先定义一个对应键结构的结构体,再实现yaml-cpp的convert模板特化:
#include <yaml-cpp/yaml.h> #include <iostream> // 定义对应复杂键的结构体 struct Resource { int cpu; int mem; }; // 给yaml-cpp添加类型转换规则 namespace YAML { template<> struct convert<Resource> { // 编码:把Resource转为YAML节点 static Node encode(const Resource& rhs) { Node node; node["cpu"] = rhs.cpu; node["mem"] = rhs.mem; return node; } // 解码:把YAML节点转为Resource static bool decode(const Node& node, Resource& rhs) { if (!node.IsMap() || !node["cpu"] || !node["mem"]) { return false; } rhs.cpu = node["cpu"].as<int>(); rhs.mem = node["mem"].as<int>(); return true; } }; } int main() { try { YAML::Node config = YAML::LoadFile("complex_keys.yaml"); // 遍历thr数组里的每个元素 for (const auto& item : config["thr"]) { // 遍历每个元素里的键值对(这里每个元素只有一个键值对) for (const auto& kv : item) { Resource key = kv.first.as<Resource>(); int value = kv.second.as<int>(); std::cout << "cpu: " << key.cpu << ", mem: " << key.mem << " -> 对应值: " << value << std::endl; } } } catch (const YAML::Exception& e) { std::cerr << "解析YAML出错:" << e.what() << std::endl; return 1; } return 0; }
这样修改后,yaml-cpp就能正确解析你原来的复杂键YAML文件了。
另外提醒下,尽量使用较新的yaml-cpp版本(比如0.7.0及以上),旧版本对复杂键的支持可能存在更多兼容性问题。
备注:内容来源于stack exchange,提问作者Olumide
相关产品推荐
相关产品推荐

