title: Manipulating nodes in yaml-cpp
body: <p>I am currently working on a project that I would like to configure using the library <a href="https://github.com/jbeder/yaml-cpp" rel="nofollow noreferrer">yaml-cpp</a>. Now I am trying to write a function which is given a vector of tags/strings (e.g., "A", "B", "C") and some parameter value (e.g., 31). The function should then insert a map node for each tag (if such a node does not already exist), map it to the subsequent node and finally create a scalar node with the parameter value. After the stated example call, the configuration should hence read</p>
  
  <pre><code>A:
    B:
      C: 31
  </code></pre>
  
  <p>Below you can see the attempt of a clean and simple implementation:</p>
  
  <p>Config.hpp</p>
  
  <pre><code>class Config {
  
  public:
  
      template&lt;typename T&gt;
      static void setConfigParam(const std::vector&lt;std::string&gt; &amp;tags,
              T value) {
          assert(tags.size() &gt; 0);
          assert(config);
          YAML::Node parentNode = config;
          for(int i=0; i &lt; tags.size()-1; i++) {
              const std::string &amp; tag = tags.at(i);
              if(parentNode[tag]) {
                  YAML::Node childNode = parentNode[tag];
                  parentNode = childNode;
              }
              else {
                  YAML::Node childNode(YAML::NodeType::Map);
                  parentNode[tag] = childNode;
                  parentNode = childNode;
              }
          }
          parentNode[tags.back()] = value;
          std::cout &lt;&lt; "Config:\n" &lt;&lt; config &lt;&lt; "\n\n";
      }
  
  private:
  
      static YAML::Node config;
  
  };
  
  YAML::Node Config::config(YAML::NodeType::Map);
  </code></pre>
  
  <p>Test.cpp</p>
  
  <pre><code>#include "Config.hpp"
  
  int main(int argc, char **argv) {
      int val1 = 3;
      vector&lt;string&gt; tags1 = {"A1","B1","C1","D1"};
      Config::setConfigParam(tags1, val1);
      string val2 = "test";
      vector&lt;string&gt; tags2 = {"A1","B1","C1","D2"};
      Config::setConfigParam(tags2, val2);
      bool val3 = true;
      vector&lt;string&gt; tags3 = {"A1","B1","C1"};
      Config::setConfigParam(tags3, val3);
      double val4 = 2.385;
      vector&lt;string&gt; tags4 = {"A1","B2","C1"};
      Config::setConfigParam(tags4, val4);
  }
  </code></pre>
  
  <p>The problem of the function <code>setConfigParam()</code> seem to be the lines</p>
  
  <pre><code>YAML::Node parentNode = config;
  </code></pre>
  
  <p>and</p>
  
  <pre><code>parentNode = childNode
  </code></pre>
  
  <p>According to my understanding from the <a href="https://github.com/jbeder/yaml-cpp/wiki/Tutorial" rel="nofollow noreferrer">tutorial</a>, the first line apparently creates the node <code>parentNode</code> as an alias for <code>config</code>. At each function call, the first execution of the second line then replaces the existing <code>config</code> object with the newly created <code>childNode</code>. However, in the remaining iterations the <code>config</code> is no longer being completely reset but adapted as expected.</p>
  
  <p>If everything was running fine, the output should be:</p>
  
  <pre><code>Config:
  A1:
    B1:
      C1:
        D1: 3
  
  Config:
  A1:
    B1:
      C1:
        D1: 3
        D2: test
  
  Config:
  A1:
    B1:
      C1: true
  
  Config:
  A1:
    B1:
      C1: true
    B2:
      C1: 2.385
  </code></pre>
  
  <p>The actual output of the code above is</p>
  
  <pre><code>Config:
  B1:
    C1:
      D1: 3
  
  Config:
  B1:
    C1:
      D2: test
  
  Config:
  B1:
    C1: true
  
  Config:
  B2:
    C1: 2.385
  </code></pre>
  
  <p>I tried to prevent the mentioned issue by using pointers and finally managed to come up with the following implementation, which works correctly at least with the test code:</p>
  
  <pre><code>template&lt;typename T&gt;
  static void setConfigParam(const std::vector&lt;std::string&gt; &amp;tags,
          T value) {
      int numTags = tags.size();
      // Reads root node.
      assert(numTags &gt; 0);
      assert(config);
      YAML::Node* parentNode = &amp;config;
      // Determines index of first non-existing node.
      int i=0;
      for(; i &lt; numTags-1; i++) {
          const std::string &amp; tag = tags.at(i);
          if((*parentNode)[tag]) {
              auto childNode = (*parentNode)[tag];
              parentNode = &amp;childNode;
          }
          else {
              break;
          }
      }
      // Note: necessary because *parentNode will later point
      // to a different node due to lib behavior .
      YAML::Node lastExistingNode = *parentNode;
      // Sets node value and creates missing nodes.
      if(i == numTags - 1) {
          lastExistingNode[tags.back()] = value;
      }
      else {
          YAML::Node newNode;
          newNode = value;
          for(int j = tags.size()-1; j&gt;i; j--) {
              YAML::Node tmpNode;
              tmpNode[tags.at(j)] = newNode;
              newNode = tmpNode;
          }
          // Inserts missing nodes.
          lastExistingNode[tags.at(i)] = newNode;
      }
      std::cout &lt;&lt; "Config:\n" &lt;&lt; config &lt;&lt; "\n\n";
  }
  </code></pre>
  
  <p>However, I believe there must be a much simpler and cleaner solution. Hence, I am very thankful for any ideas on how to get the function to work correctly with a more simple implementation, in particular as there is not too much documentation on the library.</p>