yaml-cpp для C++: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

yaml-cpp для C++: полное руководство с примерами

1. Что это и зачем нужна

yaml-cpp — это легковесная, современная библиотека на C++ для парсинга и генерации YAML-файлов. YAML (YAML Ain't Markup Language) — это формат сериализации данных, удобный для чтения человеком, который часто используется для конфигурационных файлов, описания структур данных, CI/CD пайплайнов (например, GitHub Actions, GitLab CI) и обмена данными между сервисами. В отличие от JSON, YAML поддерживает комментарии, многострочные строки, якоря и алиасы, что делает его идеальным для конфигураций.

Зачем использовать yaml-cpp? Если вы пишете на C++ приложение, которому нужно читать конфигурационные файлы (например, настройки сервера, параметры модели машинного обучения, описание зависимостей), yaml-cpp предоставляет простой и типобезопасный API. Библиотека полностью соответствует спецификации YAML 1.2, поддерживает все типы данных (скаляры, последовательности, отображения) и позволяет легко преобразовывать YAML-документы в структуры C++ и обратно.

Ключевые преимущества: минимальные зависимости (только стандартная библиотека C++11/14/17), header-only опциональная сборка, поддержка Unicode, возможность кастомной сериализации для пользовательских типов, и активное сообщество (более 5 тысяч звезд на GitHub).

2. Установка

yaml-cpp не устанавливается через пакетные менеджеры языков (pip, npm). Для C++ используются системные менеджеры пакетов или сборка из исходников.

Linux (Debian/Ubuntu)

sudo apt-get install libyaml-cpp-dev

macOS (Homebrew)

brew install yaml-cpp

Windows (vcpkg)

vcpkg install yaml-cpp

Сборка из исходников (CMake)

git clone https://github.com/jbeder/yaml-cpp.git
cd yaml-cpp
mkdir build && cd build
cmake -DYAML_BUILD_SHARED_LIBS=ON ..
make
sudo make install

После установки подключите библиотеку в CMakeLists.txt:

find_package(yaml-cpp REQUIRED)
target_link_libraries(my_project yaml-cpp)

3. Быстрый старт — минимальный рабочий пример

Создайте файл config.yaml:

server:
  host: "localhost"
  port: 8080
debug: true

Прочитаем его с помощью yaml-cpp:

#include <iostream>
#include <yaml-cpp/yaml.h>

int main() {
    // Загружаем YAML файл
    YAML::Node config = YAML::LoadFile("config.yaml");
    
    // Читаем значения
    std::string host = config["server"]["host"].as<std::string>();
    int port = config["server"]["port"].as<int>();
    bool debug = config["debug"].as<bool>();
    
    std::cout << "Host: " << host << "\n";
    std::cout << "Port: " << port << "\n";
    std::cout << "Debug: " << std::boolalpha << debug << "\n";
    
    return 0;
}

Компиляция: g++ -std=c++17 main.cpp -lyaml-cpp -o app

4. Основные методы/функции/классы

4.1. YAML::Node — основной класс для работы с узлами

Сигнатура: class YAML::Node

Описание: Представляет любой элемент YAML-документа: скаляр, последовательность (массив) или отображение (словарь). Поддерживает итерацию, доступ по ключу/индексу, проверку типа.

YAML::Node node;
node["name"] = "Alice";
node["age"] = 30;
node["hobbies"].push_back("reading");
node["hobbies"].push_back("coding");

std::cout << node["name"].as<std::string>() << "\n"; // Alice
std::cout << node["hobbies"][0].as<std::string>() << "\n"; // reading

4.2. YAML::LoadFile() — загрузка из файла

Сигнатура: YAML::Node YAML::LoadFile(const std::string& filename)

Описание: Парсит YAML-файл и возвращает корневой узел. При ошибке парсинга выбрасывает исключение YAML::BadFile или YAML::ParserException.

try {
    YAML::Node doc = YAML::LoadFile("settings.yaml");
    // работа с doc
} catch (const YAML::Exception& e) {
    std::cerr << "YAML Error: " << e.msg << "\n";
}

4.3. YAML::Load() — загрузка из строки

Сигнатура: YAML::Node YAML::Load(const std::string& input)

Описание: Парсит YAML из строки. Полезно для тестирования или получения данных из сети.

std::string yaml_str = "key: value\nlist: [1, 2, 3]";
YAML::Node node = YAML::Load(yaml_str);
std::cout << node["key"].as<std::string>() << "\n"; // value
std::cout << node["list"][1].as<int>() << "\n"; // 2

4.4. Node::as<T>() — преобразование в тип C++

Сигнатура: template<typename T> T Node::as() const

Описание: Преобразует узел в указанный тип. Поддерживает: int, double, std::string, bool, std::vector, std::map, и пользовательские типы (через специализацию).

YAML::Node node = YAML::Load("value: 42");
int val = node["value"].as<int>(); // 42

// Преобразование в вектор
YAML::Node arr = YAML::Load("[1, 2, 3]");
std::vector<int> vec = arr.as<std::vector<int>>(); // {1, 2, 3}

4.5. Node::IsScalar(), IsSequence(), IsMap() — проверка типа узла

Сигнатура: bool Node::IsScalar() const, bool Node::IsSequence() const, bool Node::IsMap() const

Описание: Проверяют, является ли узел скаляром (строка/число/буль), последовательностью (массивом) или отображением (словарем). Позволяют безопасно обрабатывать динамические структуры.

YAML::Node node = YAML::Load("mixed: [1, {a: 2}]");
if (node["mixed"].IsSequence()) {
    for (auto it = node["mixed"].begin(); it != node["mixed"].end(); ++it) {
        if (it->IsScalar()) {
            std::cout << "Scalar: " << it->as<int>() << "\n";
        } else if (it->IsMap()) {
            std::cout << "Map key 'a': " << (*it)["a"].as<int>() << "\n";
        }
    }
}

4.6. Node::push_back() — добавление элемента в последовательность

Сигнатура: void Node::push_back(const Node& value)

Описание: Добавляет элемент в конец последовательности. Если узел не был последовательностью, он становится таковой (даже если был скаляром).

YAML::Node list;
list.push_back("first");
list.push_back(2);
list.push_back(3.14);

std::cout << list.size() << "\n"; // 3
std::cout << list[1].as<int>() << "\n"; // 2

4.7. Node::remove() — удаление элемента

Сигнатура: void Node::remove(const Node& key) (для map), void Node::remove(std::size_t index) (для sequence)

Описание: Удаляет элемент по ключу (для отображений) или индексу (для последовательностей). После удаления индексы перестраиваются.

YAML::Node config = YAML::Load("{a: 1, b: 2, c: 3}");
config.remove("b"); // удаляем ключ 'b'
std::cout << config["c"].as<int>() << "\n"; // 3

YAML::Node arr = YAML::Load("[10, 20, 30]");
arr.remove(1); // удаляем элемент с индексом 1 (значение 20)
std::cout << arr[1].as<int>() << "\n"; // 30

4.8. YAML::Emitter — генерация YAML

Сигнатура: class YAML::Emitter

Описание: Позволяет создавать YAML-строку программно. Поддерживает отступы, комментарии, стили (блоковый/потоковый).

YAML::Emitter out;
out << YAML::BeginMap;
out << YAML::Key << "name";
out << YAML::Value << "Bob";
out << YAML::Key << "age";
out << YAML::Value << 25;
out << YAML::Key << "skills";
out << YAML::Value << YAML::BeginSeq;
out << "C++" << "Python" << "YAML";
out << YAML::EndSeq;
out << YAML::EndMap;

std::cout << out.c_str() << "\n";
// Вывод:
// name: Bob
// age: 25
// skills:
//   - C++
//   - Python
//   - YAML

4.9. YAML::Node::operator[] — доступ по ключу/индексу

Сигнатура: Node Node::operator[](const std::string& key) и Node Node::operator[](std::size_t index)

Описание: Предоставляет доступ к дочернему узлу. Если ключ не существует, создается новый пустой узел. Для последовательностей работает как доступ по индексу.

YAML::Node doc = YAML::Load("{user: {name: Alice}}");
doc["user"]["age"] = 30; // создаем новый ключ
std::cout << doc["user"]["age"].as<int>() << "\n"; // 30

YAML::Node list = YAML::Load("[a, b, c]");
list[3] = "d"; // расширяет массив
std::cout << list[3].as<std::string>() << "\n"; // d

4.10. YAML::Dump() — сериализация узла в строку

Сигнатура: std::string YAML::Dump(const Node& node)

Описание: Преобразует узел обратно в YAML-строку. Полезно для логирования или сохранения измененной конфигурации.

YAML::Node node;
node["title"] = "My App";
node["version"] = 1.0;
node["features"].push_back("auth");
node["features"].push_back("logging");

std::string yaml_output = YAML::Dump(node);
std::cout << yaml_output;
// Вывод:
// features:
//   - auth
//   - logging
// title: My App
// version: 1.0

5. Реальный практический пример (100-200 строк кода)

Создадим утилиту для управления конфигурацией веб-сервера: чтение, валидация, обновление и сохранение.

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <yaml-cpp/yaml.h>

struct ServerConfig {
    std::string host;
    int port;
    bool ssl;
    std::vector<std::string> allowed_origins;
    int max_connections;
};

// Пользовательская конвертация для ServerConfig
namespace YAML {
template<>
struct convert<ServerConfig> {
    static Node encode(const ServerConfig& rhs) {
        Node node;
        node["host"] = rhs.host;
        node["port"] = rhs.port;
        node["ssl"] = rhs.ssl;
        node["allowed_origins"] = rhs.allowed_origins;
        node["max_connections"] = rhs.max_connections;
        return node;
    }

    static bool decode(const Node& node, ServerConfig& rhs) {
        if (!node.IsMap()) return false;
        rhs.host = node["host"].as<std::string>();
        rhs.port = node["port"].as<                    

Рекомендаций