【问题标题】:Obtain Type of Value Stored in YAML::Node for yaml-cpp为 yaml-cpp 获取存储在 YAML::Node 中的值的类型
【发布时间】:2013-11-28 10:43:19
【问题描述】:

鉴于此代码:

void LoadFromYaml(const YAML::Node& node){
    const YAML::Node& Data=node["Data"];
    if(Data){
        if(Data.ValueIsInt)// Do something with integer.
        if(Data.ValueIsFloat)// Do something with float.
        if(Data.ValueIsString)// Do something with string.
    }
}

如何检查 YAML 节点“数据”中包含的数据是整数、浮点数还是字符串?注意:我不想检查 Node 是否是标量、映射、序列等。

【问题讨论】:

    标签: c++ yaml-cpp


    【解决方案1】:

    解析时抛出大量异常会影响解析速度。不知道为什么yamlcpp 没有is_type<T> 方法或类似于std::optionalstd::expected getters 的方法

    使用 Boost 解决此问题的黑客方法 - 将您自己的模板特化注入 YAML 命名空间并返回 boost::optional(或 std::optional,如果您有 C++17)

    namespace YAML
    {
        template <typename T>
        struct as_if<T, boost::optional<T> >
        {
            explicit as_if(const Node& node_) : node(node_) {}
            const Node& node;
    
            const boost::optional<T> operator()() const
            {
                boost::optional<T> val;
                T t;
                if (node.m_pNode && convert<T>::decode(node, t))
                    val = std::move(t);
    
                return val;
            }
        };
    
        // There is already a std::string partial specialisation, so we need a full specialisation here
        template <>
        struct as_if<std::string, boost::optional<std::string> >
        {
            explicit as_if(const Node& node_) : node(node_) {}
            const Node& node;
    
            const boost::optional<std::string> operator()() const
            {
                boost::optional<std::string> val;
                std::string t;
                if (node.m_pNode && convert<std::string>::decode(node, t))
                    val = std::move(t);
    
                return val;
            }
        };
    }
    

    然后你可以运行类似的东西

    boost::optional<bool> as_bool          = YAML::as_if<bool, boost::optional<bool> >(node)();
    boost::optional<int> as_int            = YAML::as_if<int, boost::optional<int> >(node)();
    boost::optional<double> as_double      = YAML::as_if<double, boost::optional<double> >(node)();
    boost::optional<std::string> as_string = YAML::as_if<std::string, boost::optional<std::string> >(node)();
    

    这里的总建设成本是 4 个可选值 + 4 个默认值。这可能会也可能不会比处理异常更快,我没有测试过。

    【讨论】:

    • 天哪,谢谢你的回答!我实际上忘记了我有这个问题。异常非常慢,因为它们展开堆栈,所以我想您的解决方案非常快。
    • 是的,我想是的 - 像std::expected 这样的提议的全部基本原理是让此类事情的成功和失败路径同等重要。但是把它留在里面,这样人们就知道要做功课了。我在一个插入式 .d 样式的 YAML 解析器中使用了它,因此我们期望我们事先几乎不知道文档的外观 - 因此尽可能避免异常。
    【解决方案2】:

    您可以尝试将节点转换为每种类型:

    try {
      int value = data.as<int>();
      // do something
    } catch (const BadConversion& e) {
      // do something else
    }
    

    【讨论】:

    • 谢谢,但是对于 3 种类型的 try/catch 块串联编码的好方法是什么?还是嵌套它是唯一的方法?
    • 是的;当有几个是真的时,你必须决定你想要什么行为。例如,它总是一个字符串(如果它是一个标量),如果它是一个 int,它也将是一个浮点数。
    • 好的,测试浮点数,然后是 int,然后是 string 应该可以解决问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-06
    • 1970-01-01
    相关资源
    最近更新 更多