1

This is my first experience with boost::property_tree and I can't find a way to reproduce the way to get values from a tree following the documentation (How to Access Data in a Property Tree). This is the simple code that I wrote to experiment with a property tree:

#include <iostream>
#include <string>

#include <boost/property_tree/info_parser.hpp>
#include <boost/property_tree/ptree.hpp>

namespace pt = boost::property_tree;

int main(int argc, char *argv[]) {
  pt::ptree tree;

  tree.put("pi", 3.14159);
  tree.put("name", "John Doe");

  for (auto &[key, value] : tree)
    std::cout << key << " : " << value.get_value<std::string>() << "\n";

  std::cout << "pi : " << tree.get_value("pi") << "\n";
  std::cout << "name : " << tree.get_value("name") << "\n";

  auto pi = tree.get_optional<float>("pi").get();
  std::cout << "pi optional : " << pi << "\n";

  auto pi_found = tree.find("pi");
  std::cout << "pi found : " << pi_found->second.data() << "\n";

  // the commented line doesn't compile
  // std::cout << "not found : " << tree.get_value<int>("null") << "\n";

  std::cout << "not found : " << tree.get_value("null") << "\n";

  // the line below causes an assertion error:
  // Assertion failed: (this->is_initialized()), function get, file /usr/local/include/boost/optional/optional.hpp, line 1191.
  // not found : Abort trap: 6
  std::cout << "not found : " << tree.get_optional<int>("null").get() << "\n";

  pt::write_info("ptree.info", tree);

  return 0;
}

This is the output:

pi : 3.1415899999999999
name : John Doe
pi :
name :
pi optional : 3.14159
pi found : 3.1415899999999999
not found :

As can be seen tree.get_value("whatever") returns no value, tree.get_value("null") does not throw an exception and get_optional<whatever type> does not compile. My experiment behaves way too different from the stated in the documentation. Excluding the line that causes the assertion error creates the output info file as expected.

My environment is:

MacOS 10.11.6
macbrew installed tools and libraries
boost 1.67
clang 7.0
meson build system
Angelo
  • 51
  • 1
  • 5

2 Answers2

1

You can draw your ptree as:

node1 is tree (has 2 children, data() of tree is "")
 |
 |- (node2) pi ----> data=3.14...
 |
 |- (node3) name --> data="Joe Doe"

[1]

As can be seen tree.get_value("whatever") returns no value

tree is node and has 2 children (pi, name). While calling

tree.get_value(defaultValue) // you are not passing PATH, but DEFAULT VALUE

above line is translated into

tree.get_child("").get_value(defaultValue)

so, "" path exists because it is path to tree node, and tree.data() returns "" - empty string for this path. So defaultValue cannot be printed and you see empty string as output. You should call get_value only for children (use get_child on tree before calling this methid, it is described in boost reference), and parameter of get_value is default value. So replace

  std::cout << "pi : " << tree.get_child("pi").get_value("PI is 4.0") << "\n";
  std::cout << "name : " << tree.get_child("name").get_value("noname") << "\n";

you will see 3.14 and Joe Doe.

[2]

tree.get_value("null") does not throw an exception

is was described in [1] point. "" path exists, and data() for this path is empty string. So you cannot see null string as default value.

[3]

// the commented line doesn't compile // std::cout << "not found : "

<< tree.get_value("null") << "\n";

This line cannot be compiled because ptree class doesn't have that method, I suppose you want to call this method:

  template<typename Type> 
  unspecified get_value(const Type & default_value) const;

you defined Type as int, int as function template parameter involves that default value can be only int, not string.

Community
  • 1
  • 1
rafix07
  • 20,001
  • 3
  • 20
  • 33
  • In your question you put link to boost reference, on this page there is no use of `get_value`, this function is only mentioned, but there is very important sentence `Don't call get with and empty path to do this as it will try to extract contents of subkey with empty name.` -> `get_value() == get_child("").get_value()` see this page https://www.boost.org/doc/libs/1_65_1/boost/property_tree/ptree.hpp. – rafix07 Sep 25 '18 at 17:44
  • Hi @rafix07, thank you very much for you answer. The lib documentation is way too different from what you showed. For instance, from the page on how to get values states: `float v = pt.get("a.path.to.float.value");` It is misleading and doesn't correspond to how the lib really works. Regarding your suggestions, the following works: `std::cout << "pi : " << tree.get_child("pi").get_value() << "\n";` – Angelo Sep 25 '18 at 17:45
  • you are right, I took `get_value` from the for loop and pasted it without much concern. This is the way to go `tree.get("pi")` – Angelo Sep 25 '18 at 17:49
0

My bad, instead of using tree.get<float>("pi") I copied and pasted tree.get_value<float>("pi") that is meant for a different use. The question is answered with the help of @rafix07 comment. The get<type>("key path") is the correct method to use.

Angelo
  • 51
  • 1
  • 5
  • @rafix07's post is not a comment, it's a full-blown answer. Instead of posting your comment as an answer, you should probably upvote his answer and accept it. See https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – sehe Sep 26 '18 at 08:32