我在boost property_tree的头文件中迷失了,并且由于缺少关于较低层的文档,我决定问一下简单的方法是覆盖流转换器来改变布尔值的方式被解析。
问题是在属性树的输入端有用户,他们可以修改配置文件。可以通过多种方式指定布尔值,例如:
dosomething.enabled=true
dosomething.enabled=trUE
dosomething.enabled=yes
dosomething.enabled=ON
dosomething.enabled=1
默认行为是检查0或1,然后使用
std::ios_base::boolalpha
让流尝试以适当的方式解析当前语言环境的值...如果我们尝试将配置文件发送给国际客户,这可能是疯了。
那么最简单的方法是覆盖这种行为或bool只是什么?不仅最容易实现,而且最容易使用 - 因此我的类的用户从iptree派生出来不需要为布尔值做一些特别的事情。
谢谢!
答案 0 :(得分:21)
您可以专门化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";
}
test.json:
{
"number" : 42,
"enabled" : "Yes"
}
输出:
i=42 b=1
请注意,此示例假定属性树不区分大小写并使用std::string
。如果您希望BoolTranslator
更加通用,则必须使BoolTranslator
成为模板,并为宽字符串和区分大小写的比较提供专业化。
答案 1 :(得分: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);