yaml-cpp is a C++ library for parsing and generating YAML. It loads YAML data
into a tree of YAML::Node objects. A node may contain a mapping, sequence, or
scalar value, and .as<T>() converts a scalar to a C++ type.
This minimal C++17 example reads an application configuration from a file. It
does not modify or write YAML.
A YAML sequence can be traversed with a range-based for loop.
Parsing and conversion can fail
YAML::LoadFile throws when the file cannot be opened or parsed. .as<T>()
throws when a required value is missing or cannot be converted to T. The
example catches YAML::Exception, prints the error, and exits with a
non-zero status.
cmake_minimum_required(VERSION3.16)project(yaml_read_demoLANGUAGESCXX)find_package(yaml-cppREQUIRED)add_executable(read_yamlmain.cpp)target_link_libraries(read_yamlPRIVATEyaml-cpp::yaml-cpp)target_compile_features(read_yamlPRIVATEcxx_std_17)target_compile_options(read_yamlPRIVATE-Wall-Wextra-pedantic)# Copy the example configuration into the build directory.configure_file(config.yamlconfig.yamlCOPYONLY)
find_package locates the Ubuntu development package. The imported target
supplies the include directories and library required by read_yaml:
The first example accesses each YAML node directly. That is useful for small
files, but configuration code becomes difficult to maintain when the same keys
are read in many places. A typed configuration keeps the rest of the program
independent from the YAML tree:
config.yaml C++
----------- ---
app -> Config::app
name -> AppConfig::name
port -> AppConfig::port
features -> Config::features
Define a yaml-cpp conversion
yaml-cpp already knows how to convert scalars and standard containers such as
std::vector<std::string>. It does not know the meaning of application types
such as AppConfig, so the example specializes YAML::convert<T>:
Convert each value into the corresponding structure member.
Returning false tells yaml-cpp that the node cannot be converted to the
requested type. Scalar conversions such as .as<int>() can also throw when a
value has the wrong type.
Config has its own conversion and can reuse the nested conversion:
After this line, normal application code uses config.app.name and
config.features; it no longer needs to know YAML key paths.
Keep parsing at the application boundary
Convert YAML into typed configuration objects near program startup. Pass
those objects to the rest of the application instead of passing
YAML::Node everywhere. This keeps yaml-cpp details out of business logic.
Validate meaning separately
Successful type conversion does not prove that a value is sensible. Add
application checks for rules such as 1 <= port <= 65535, non-empty names,
and permitted feature values.
When node["app"] = value.app is evaluated, yaml-cpp finds the
YAML::convert<AppConfig>::encode specialization. It already knows how to
encode std::vector<std::string>.
Read, update, and save
First load the YAML file into a mutable structure:
constYAML::Nodeoutput_node=YAML::convert<Config>::encode(config);std::ofstreamoutput(output_path);if(!output){std::cerr<<"Cannot open output file: "<<output_path<<'\n';return1;}output<<output_node;
Encoding reconstructs the document
This method creates a new YAML document from the mapped fields. Comments,
original formatting, key order, and unknown keys are not guaranteed to be
preserved. Use it for application-owned configuration rather than as a
general-purpose editor for human-authored YAML.
Write to a separate file first
The example defaults to struct_updated.yaml, leaving config.yaml
unchanged. For important configuration, write a temporary file, verify the
stream succeeded, and atomically replace the destination only after the
complete document is safely written.
#include<yaml-cpp/yaml.h>#include<fstream>#include<iostream>#include<string>#include<vector>structAppConfig{std::stringname;intport;};structConfig{AppConfigapp;std::vector<std::string>features;};namespaceYAML{template<>structconvert<AppConfig>{// Convert a C++ struct into a YAML node.staticNodeencode(constAppConfig&value){Nodenode;node["name"]=value.name;node["port"]=value.port;returnnode;}// Convert a YAML node into a C++ struct.staticbooldecode(constNode&node,AppConfig&value){if(!node.IsMap()||!node["name"]||!node["port"]){returnfalse;}value.name=node["name"].as<std::string>();value.port=node["port"].as<int>();returntrue;}};template<>structconvert<Config>{staticNodeencode(constConfig&value){Nodenode;node["app"]=value.app;node["features"]=value.features;returnnode;}staticbooldecode(constNode&node,Config&value){if(!node.IsMap()||!node["app"]||!node["features"]){returnfalse;}value.app=node["app"].as<AppConfig>();value.features=node["features"].as<std::vector<std::string>>();returntrue;}};}// namespace YAMLintmain(intargc,char*argv[]){conststd::stringinput_path=argc>1?argv[1]:"config.yaml";conststd::stringoutput_path=argc>2?argv[2]:"struct_updated.yaml";try{// 1. Load YAML into the structure.Configconfig=YAML::LoadFile(input_path).as<Config>();// 2. Update ordinary C++ members.config.app.name="updated-yaml-demo";config.app.port=9090;config.features.push_back("struct-mapping");// 3. Convert the structure back into YAML and save a new file.constYAML::Nodeoutput_node=YAML::convert<Config>::encode(config);std::ofstreamoutput(output_path);if(!output){std::cerr<<"Cannot open output file: "<<output_path<<'\n';return1;}output<<output_node;std::cout<<"Saved updated struct to "<<output_path<<'\n';}catch(constYAML::Exception&error){std::cerr<<"YAML error: "<<error.what()<<'\n';return1;}return0;}
The page's CMakeLists.txt builds a third executable: