14

我迷失在 boost property_tree 的头文件中,并且由于缺乏较低层的文档,我决定问什么简单的方法是覆盖流转换器以更改布尔值的解析方式。

问题是在属性树的输入端,有用户,他们可以修改配置文件。可以通过多种方式指定布尔值,例如:

dosomething.enabled=true
dosomething.enabled=trUE
dosomething.enabled=yes
dosomething.enabled=ON
dosomething.enabled=1

默认行为是检查 0 或 1,然后使用

std::ios_base::boolalpha 

让流尝试以适当的方式解析当前语言环境的值...如果我们尝试将配置文件发送给国际客户,这可能会很疯狂。

那么覆盖此行为或仅使用布尔值的最简单方法是什么?不仅最容易实现,而且最容易使用——这样从 iptree 派生的类的用户不需要为布尔值做一些特殊的事情。

谢谢!

4

2 回答 2

22

您可以专门化boost::property_tree::translator_between,以便属性树将自定义转换器用于bool值类型。#includ想要定制行为的客户必须能够看到(即编辑)这种专业化。这是一个工作示例:

#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/algorithm/string/predicate.hpp>

// Custom translator for bool (only supports std::string)
struct BoolTranslator
{
    typedef std::string internal_type;
    typedef bool        external_type;

    // Converts a string to bool
    boost::optional<external_type> get_value(const internal_type& str)
    {
        if (!str.empty())
        {
            using boost::algorithm::iequals;

            if (iequals(str, "true") || iequals(str, "yes") || str == "1")
                return boost::optional<external_type>(true);
            else
                return boost::optional<external_type>(false);
        }
        else
            return boost::optional<external_type>(boost::none);
    }

    // Converts a bool to string
    boost::optional<internal_type> put_value(const external_type& b)
    {
        return boost::optional<internal_type>(b ? "true" : "false");
    }
};

/*  Specialize translator_between so that it uses our custom translator for
    bool value types. Specialization must be in boost::property_tree
    namespace. */
namespace boost {
namespace property_tree {

template<typename Ch, typename Traits, typename Alloc> 
struct translator_between<std::basic_string< Ch, Traits, Alloc >, bool>
{
    typedef BoolTranslator type;
};

} // namespace property_tree
} // namespace boost

int main()
{
    boost::property_tree::iptree pt;

    read_json("test.json", pt);
    int i = pt.get<int>("number");
    int b = pt.get<bool>("enabled");
    std::cout << "i=" << i << " b=" << b << "\n";
}

测试.json:

{
    "number" : 42,
    "enabled" : "Yes"
}

输出:

i=42 b=1

请注意,此示例假定属性树不区分大小写并使用std::string. 如果您想BoolTranslator更通用,则必须制作BoolTranslator一个模板并为宽字符串和区分大小写的比较提供专业化。

于 2012-03-17T21:44:07.490 回答
1

theboostcpplibraries.com上也有一个很好的例子。

基于此,我编写了一个自定义解析器(省略了声明):

boost::optional<bool> string_to_bool_translator::get_value(const std::string &s) {
    auto tmp = boost::to_lower_copy(s);
    if (tmp == "true" || tmp == "1" || tmp == "y" || tmp == "on") {
       return boost::make_optional(true);
    } else if (tmp == "false" || tmp == "0" || tmp == "n" || tmp == "off") {
      return boost::make_optional(false);
    } else {
        return boost::none;
    }
} 

它仅适用于 bool 和 std::string 但易于扩展。

然后,

boost::property_tree::ptree pt;
...
string_to_bool_translator tr;
auto optional_value = pt.get_optional<bool>(key, tr);
于 2017-02-07T07:55:56.270 回答