I need to parse some YAML in C++ (sort of newish to YAML). I'm looking to use yaml-cpp. My objectives are:
If I take some example YAML, it might appear as:
...
comms:
messageBus:
remoteHost: "message-bus"
remotePort: 5672
or even:
...
comms:
Nonetheless, I want to be able to update YAML reflecting default values. So to read the above YAML, the code would look something like:
auto &nodeComms = get_yaml_node_field_or_insert(node, "comms");
auto &nodeMessageBus = get_yaml_node_field_or_insert(nodeComms , "comms");
auto strRemoteHost = get_yaml_string_field_or_default_and_update(nodeMessageBus, "remoteHost", "127.0.0.1");
auto nRemotePort = get_yaml_uint16_field_or_default_and_update(nodeMessageBus, "remotePort", uint16_t{5672});
so that if the above code is run on the second example, the updated YAML would now be:
...
comms:
messageBus:
remoteHost: "127.0.0.1"
remotePort: 5672
For both get_yaml_string_field_or_default_and_update
and get_yaml_uint16_field_or_default_and_update
, it's fairly trivial to create a templated function to handle reading different value types and inserting them if necessary:
///////////////////////////////////////////////////////////////////////////
template <typename TYPE_IN, typename TYPE_RETURN>
TYPE_RETURN get_type_from_yaml_node_or_default_and_update(YAML::Node &node,
const char *pchFieldName,
TYPE_IN nValueDefault) noexcept
{
if (!node)
{
assert(false);
throw std::runtime_error("Invalid node");
}
if (!node[pchFieldName])
{
node[pchFieldName] = nValueDefault;
return nValueDefault;
}
try
{
return node[pchFieldName].as<TYPE_RETURN>();
}
catch (const std::exception &e)
{
node[pchFieldName] = nValueDefault;
return nValueDefault;
}
catch (...)
{
node[pchFieldName] = nValueDefault;
return nValueDefault;
}
}
The code I'm struggling with is get_yaml_node_field_or_insert
:
///////////////////////////////////////////////////////////////////////////
YAML::Node &get_yaml_node_field_or_insert(YAML::Node &node, const char *pchFieldName) noexcept
{
if (!node)
{
assert(false);
throw std::runtime_error("Invalid node");
}
// TODO: Either 1) Return reference if it exists or 2) insert if it does not and return reference.
return node[pchFieldName];
}
It looks as if the operator[] does not return a reference according to API.
// indexing
template <typename Key>
const Node operator[](const Key& key) const;
template <typename Key>
Node operator[](const Key& key);
Any tips/suggestions would be greatly appreciated.
YAML::Node is a reference type already, so returning it from a function doesn’t make a deep copy. It’s also mutable, so you can just edit it and the change will update the root node.