Почему mapToPt
является участником, когда он также ожидает указатель на Params
экземпляр?
В любом случае, существует некоторая путаница.
На уровне проектирования ваш тип Params
выглядит так, как будто он не может решить, является ли он листовым узлом или нет.Кроме того, он страдает от дизайна «квази-классов», где геттеры по существу гарантируют, что не возможен инвариант класса.В таких случаях предпочитайте просто иметь структуру с полями-членами.
Обратите внимание: если вам не удастся вернуть по ссылке из getParamMap()
и getChildren()
, то у вас уже есть Неопределенное поведение в обоих циклах, поскольку итераторы затем указывают на несуществующие копии контейнеров.
Вы должны проверить это.Также см. Мою рабочую демонстрацию ниже
На уровне реализации это вызывает у вас проблемы:
pt::ptree new_tree;
root.add_child(it->second->getName(), new_tree);
add_child
вставляет копию new_tree
.Любая будущая модификация new_tree
не имеет никакого эффекта.Вместо этого напишите:
pt::ptree& new_tree = root.add_child(it->second->getName(), {});
Здесь new_tree
становится ссылкой на фактически добавленное дерево.
Попытка исправить
Стильвсе еще ниже моих ожиданий.Лично я бы внимательно рассмотрел использование shared_ptr
в этом фрагменте кода.
Но это, вероятно, поможет вам в этом:
LiveНа Coliru
#include <boost/make_shared.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
#include <map>
namespace pt = boost::property_tree;
struct Param {
std::string getValue() const { return "42"; }
};
struct Params {
using ParamMap = std::map<std::string, boost::shared_ptr<Param> >;
using Children = std::map<std::string, boost::shared_ptr<Params> >;
Params(std::string name = "") : _name(name) {}
std::string getName() const { return _name; }
ParamMap& getParamMap() { return _map; }
ParamMap const& getParamMap() const { return _map; }
bool hasChildren() const { return !_children.empty(); }
Children& getChildren() { return _children; }
Children const& getChildren() const { return _children; }
static void mapToPt(boost::shared_ptr<Params> curParams, pt::ptree &root);
private:
std::string _name;
ParamMap _map;
Children _children;
};
void Params::mapToPt(boost::shared_ptr<Params> curParams, pt::ptree &root) {
// Fill current root with parameters from curParams ParameterMap
std::map<std::string, boost::shared_ptr<Param> >::iterator it;
for (it = curParams->getParamMap().begin(); it != curParams->getParamMap().end(); it++) {
root.put(it->first, it->second->getValue());
//std::cout << "Add Parameter: \n";
//std::cout << "Parameter name: " << it->first << "\n";
//std::cout << "Parameter value: " << it->second->getValue() << "\n";
}
// Recursively go through all children to do the same to them
if (curParams->hasChildren()) {
for (auto it = curParams->getChildren().begin(); it != curParams->getChildren().end(); it++) {
pt::ptree& new_tree = root.add_child(it->second->getName(), {});
//std::cout << "Add Child: \n";
//std::cout << "Child name: " << it->second->getName() << "\n";
mapToPt(it->second, new_tree);
}
}
}
int main() {
auto a = boost::make_shared<Params>("rootparams");
a->getParamMap().emplace("one", boost::make_shared<Param>());
a->getParamMap().emplace("two", boost::make_shared<Param>());
a->getParamMap().emplace("three", boost::make_shared<Param>());
a->getChildren().emplace("child1", boost::make_shared<Params>("child1-name"))
.first->second->getParamMap().emplace("four", boost::make_shared<Param>());
a->getChildren().emplace("child2", boost::make_shared<Params>("child2-name"))
.first->second->getParamMap().emplace("five", boost::make_shared<Param>());
pt::ptree root;
a->mapToPt(a, root);
write_json(std::cout, root);
}
Печать
{
"one": "42",
"three": "42",
"two": "42",
"child1-name": {
"four": "42"
},
"child2-name": {
"five": "42"
}
}