Дерево свойств Boost выглядит как отличная библиотека для разбора конфигурационных файлов. Тем не менее, я не могу понять, как обрабатывать ситуации, когда существует несколько значений на ключ. Например, допустим, я указывал поле вроде этого:
box
{
x -1 1
y -1 1
z -1 1
}
где x
, y
, а также z
границы коробки на x
, y
, а также z
оси соответственно, указанные в формате INFO property_tree. Я вижу упоминание в руководстве об использовании кавычек для значений, которые используют пробелы, но потом я не вижу, что я мог бы импортировать эти значения в виде чисел. Я должен был бы разобрать строку в числа, что, кажется, побеждает цель использования property_tree в первую очередь. Я, конечно, мог бы дать каждому числу ключ:
box
{
xlo -1
xhi 1
ylo -1
yhi 1
zlo -1
zhi 1
}
но это кажется громоздким и раздувает мой конфигурационный файл. Я также отметил, что могу справиться с этой ситуацией в program_options, но я теряю возможности вложенного файла конфигурации (да, я знаю, что могу использовать точечную нотацию для «вложения», но это не то же самое).
Есть ли способ импортировать, например, х как список чисел, как это?
Стандартное свойство property_tree обрабатывает только одно строковое значение для каждого ключа, поскольку оно определяется как:
typedef basic_ptree<std::string, std::string> ptree;
Таким образом, единственный вариант — использовать строки и анализировать их. Я думаю, что лучший метод — это определить новый класс, который хранит низкие и высокие значения, а затем создать класс переводчика для методов get и set. Например:
struct low_high_value
{
low_high_value() : m_low(0), m_high(0) { }
low_high_value(double low, double high) : m_low(low), m_high(high) { }
double m_low;
double m_high;
};
Переводчик будет:
struct low_high_value_translator
{
typedef std::string internal_type;
typedef low_high_value external_type;
// Get a low_high_value from a string
boost::optional<external_type> get_value(const internal_type& str)
{
if (!str.empty())
{
low_high_value val;
std::stringstream s(str);
s >> val.m_high >> val.m_low;
return boost::optional<external_type>(val);
}
else
return boost::optional<external_type>(boost::none);
}
// Create a string from a low_high_value
boost::optional<internal_type> put_value(const external_type& b)
{
std::stringstream ss;
ss << b.m_low << " " << b.m_high;
return boost::optional<internal_type>(ss.str());
}
};
Предыдущий метод get_value очень прост. Это должно быть улучшено, если файл может быть написан пользователем.
Этот класс должен быть зарегистрирован с использованием:
namespace boost { namespace property_tree
{
template<typename Ch, typename Traits, typename Alloc>
struct translator_between<std::basic_string< Ch, Traits, Alloc >, low_high_value>
{
typedef low_high_value_translator type;
};
} }
После включения предыдущего кода вы можете использовать property_tree как:
pt.get<low_high_value>("box.x")
pt.put("box.u", low_high_value(-110, 200));
Других решений пока нет …