How to Iterate Over YAML Sequences and Maps in yaml-cpp: A Complete Guide

yaml-cpp provides a standard C++ iterator interface via YAML::Node::begin() and end() that yields YAML::Node references for sequences and std::pair-like iterator_value objects for maps, allowing range-based for loops and STL algorithms to traverse YAML documents naturally.

The yaml-cpp library parses YAML documents into a tree of YAML::Node objects. Whether you're processing configuration files or data pipelines, understanding how to traverse sequences (arrays) and maps (dictionaries) efficiently is essential for robust C++ applications. This guide explains the iterator architecture implemented in the jbeder/yaml-cpp repository and provides practical examples for iterating over YAML nodes.

Understanding the Iterator Architecture

According to the yaml-cpp source code, the iteration mechanism relies on a template-based foundation that abstracts the differences between sequence and map traversal. The public API exposes familiar begin() and end() methods on YAML::Node objects, but the underlying implementation distinguishes between node types through the detail::iterator_base<V> template.

In include/yaml-cpp/node/node.h, the YAML::Node class declares begin() and end() methods that return forward iterators. These methods instantiate iterator_base<detail::iterator_value>, defined in include/yaml-cpp/node/detail/iterator_fwd.h via the type aliases YAML::iterator and YAML::const_iterator.

The core implementation resides in include/yaml-cpp/node/detail/iterator.h. Here, the iterator_base template implements the forward-iterator requirements, while include/yaml-cpp/node/iterator.h defines detail::iterator_value. This struct inherits from Node but exposes first and second members (representing key and value) when iterating over maps.

How iterator_value Handles Node Types

When dereferencing an iterator, the operator* implementation (found in detail::iterator_base) constructs an iterator_value based on the underlying node structure:

  • For sequences: The iterator yields a Node representing the element at that index.
  • For maps: The iterator yields an iterator_value where first contains the key node and second contains the value node.

This design allows the same C++ iteration syntax to work seamlessly across both data structures.

Code Examples for yaml-cpp Iteration

Iterating Over a Sequence

When processing a YAML sequence (e.g., [1, 2, 3]), each dereferenced iterator returns a YAML::Node representing the scalar or complex element at that position:

YAML::Node root = YAML::Load("[1, 2, 3]");
for (const YAML::Node& elem : root) {          // elem is a Node
    std::cout << elem.as<int>() << '\n';
}

The elem variable is a Node object, allowing direct conversion to native C++ types via as<T>().

Iterating Over a Map

For YAML maps (e.g., {a: 10, b: 20}), the iterator returns a detail::iterator_value that exposes first (the key) and second (the value) as Node references:

YAML::Node root = YAML::Load("{a: 10, b: 20, c: 30}");
for (const YAML::Node& entry : root) {        // entry is iterator_value
    const YAML::Node& key   = entry.first;    // key node
    const YAML::Node& value = entry.second;   // value node
    std::cout << key.Scalar() << ": " << value.as<int>() << '\n';
}

Because iterator_value inherits from Node, you can use entry directly where a Node is expected, but accessing first and second is required to separate keys from values.

Using STL Algorithms

The forward-iterator implementation in yaml-cpp supports standard C++ algorithms. You can pass map.begin() and map.end() to functions like std::accumulate:

YAML::Node map = YAML::Load("{x: 5, y: 7, z: 2}");
int sum = std::accumulate(map.begin(), map.end(), 0,
    [](int acc, const YAML::Node& pair) {
        return acc + pair.second.as<int>();   // pair.second is the value
    });
std::cout << "Sum = " << sum << '\n';

This works because map.end() returns a valid sentinel iterator and dereferenced iterators expose the second member for value access.

Const vs. Mutable Iterators

The library provides both mutable and const iterators via iterator_fwd.h. Use const YAML::Node& for read-only access or YAML::Node& to modify values in place:

YAML::Node mutableRoot = YAML::Load("[10, 20]");
for (YAML::Node& n : mutableRoot) {   // mutable reference
    n = n.as<int>() * 2;              // modify in-place
}

The begin() and end() methods return appropriate iterator types based on the const-qualification of the YAML::Node instance.

Key Source Files in yaml-cpp

Understanding the iterator implementation requires examining these specific files in the jbeder/yaml-cpp repository:

Summary

  • yaml-cpp exposes standard forward iterators via YAML::Node::begin() and end(), supporting range-based for loops and STL algorithms.
  • Sequence iteration yields YAML::Node objects directly, allowing immediate conversion to C++ types.
  • Map iteration yields detail::iterator_value objects with first (key) and second (value) members to access paired data.
  • The implementation supports both const and mutable access patterns, enabling read-only traversal or in-place modification.
  • Core iterator logic resides in node.h, iterator_fwd.h, and the detail/iterator.h implementation files.

Frequently Asked Questions

What is the difference between YAML::iterator and YAML::const_iterator?

YAML::iterator (defined in iterator_fwd.h) allows modification of the underlying YAML::Node elements during iteration, while YAML::const_iterator provides read-only access. The begin() and end() methods return the appropriate type based on the const-qualification of the node. For mutable nodes, use YAML::Node& elem in your loop; for const nodes, use const YAML::Node& elem.

How do I check if a YAML node is a sequence or map before iterating?

Use the IsSequence() or IsMap() methods on the YAML::Node object before entering the loop. For example:

if (node.IsSequence()) {
    for (const auto& elem : node) { /* sequence logic */ }
} else if (node.IsMap()) {
    for (const auto& pair : node) { /* map logic using pair.first/second */ }
}

This prevents runtime errors when accessing first or second on sequence nodes that don't expose those members.

Can I modify YAML values while iterating over a map?

Yes, if you use a non-const iterator. Declare your loop variable as YAML::Node& entry (instead of const YAML::Node& entry), then assign to entry.second to update the value. Note that you cannot modify the key (entry.first) during iteration, as this would violate the map's structural integrity. For sequences, you can modify the element directly via the loop reference.

What type does the iterator dereference operator return for sequences vs maps?

According to the implementation in detail/iterator.h, the dereference operator returns a detail::iterator_value in both cases. However, for sequences, this object behaves like a single YAML::Node representing the element. For maps, the same struct exposes first and second members containing the key and value nodes respectively. This unified interface allows the same iteration syntax to work for both node types while providing map-specific accessors when needed.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →