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

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

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

Начать курс

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

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

TOML (Tom's Obvious Minimal Language) — это формат файлов конфигурации, созданный как альтернатива INI, YAML и JSON. Он спроектирован так, чтобы быть максимально читаемым для человека, однозначно маппиться в хеш-таблицы и быть простым для парсинга. В отличие от YAML, TOML не допускает двусмысленностей (например, с отступами или типами данных), а в отличие от JSON — не требует кавычек для ключей и поддерживает комментарии.

toml++ (также известный как tomlplusplus) — это современная, header-only (заголовочная) библиотека для парсинга и генерации TOML-файлов на C++17 и выше. Она не требует сборки: вы просто подключаете заголовочный файл и получаете полный функционал. Это делает её идеальным выбором для проектов, где важна простота интеграции, производительность и строгая типизация.

Зачем использовать toml++? Во-первых, она предоставляет полную поддержку спецификации TOML v1.0, включая встроенные таблицы, массивы таблиц, даты, времена и локальные даты. Во-вторых, она написана с упором на безопасность типов: вы получаете не сырой JSON-like объект, а строго типизированные значения (std::string, int64_t, double, bool, toml::date и т.д.). В-третьих, она невероятно быстрая и имеет минимальное количество зависимостей (только стандартная библиотека C++17).

2. Установка

toml++ — это header-only библиотека. Это означает, что вам не нужно компилировать её отдельно. Достаточно скопировать заголовочные файлы в ваш проект и подключить их.

Способ 1: Vcpkg (рекомендуемый для Windows и Linux)

# Установка через vcpkg
vcpkg install tomlplusplus

# Подключение в CMakeLists.txt
find_package(tomlplusplus CONFIG REQUIRED)
target_link_libraries(my_project PRIVATE tomlplusplus::tomlplusplus)

Способ 2: Conan

# Установка через Conan
conan install tomlplusplus/3.4.0@

# В conanfile.txt
[requires]
tomlplusplus/3.4.0

[generators]
CMakeDeps

Способ 3: Ручная установка (проще всего)

# Скачайте последний релиз с GitHub
wget https://github.com/marzer/tomlplusplus/archive/refs/tags/v3.4.0.tar.gz
tar -xzf v3.4.0.tar.gz

# Скопируйте папку include/toml++ в ваш проект
cp -r tomlplusplus-3.4.0/include/toml++ /path/to/your/project/include/

# В вашем коде просто подключайте:
#include <toml++/toml.h>

Способ 4: CMake FetchContent (для CMake проектов)

include(FetchContent)
FetchContent_Declare(
    tomlplusplus
    GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
    GIT_TAG v3.4.0
)
FetchContent_MakeAvailable(tomlplusplus)

target_link_libraries(my_project PRIVATE tomlplusplus::tomlplusplus)

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

Создадим файл config.toml:

# config.toml
title = "Пример конфигурации"

[server]
host = "localhost"
port = 8080
debug = true

[database]
name = "mydb"
user = "admin"
password = "secret123"

Теперь напишем C++ код для его чтения:

#include <toml++/toml.h>
#include <iostream>
#include <filesystem>

int main() {
    // 1. Парсим файл
    auto config = toml::parse_file("config.toml");

    // 2. Читаем простые значения
    std::string title = config["title"].value_or("default");
    std::cout << "Title: " << title << std::endl;

    // 3. Читаем вложенные таблицы
    auto server = config["server"];
    std::string host = server["host"].value_or("localhost");
    int port = server["port"].value_or(3000);
    bool debug = server["debug"].value_or(false);

    std::cout << "Server: " << host << ":" << port
              << " (debug: " << std::boolalpha << debug << ")" << std::endl;

    // 4. Читаем другую таблицу
    auto database = config["database"];
    std::string db_name = database["name"].value_or("unknown");
    std::cout << "Database: " << db_name << std::endl;

    return 0;
}

Компиляция (если toml++ в папке include):

g++ -std=c++17 -I./include main.cpp -o main
./main

Вывод:

Title: Пример конфигурации
Server: localhost:8080 (debug: true)
Database: mydb

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

4.1. toml::parse_file()

Сигнатура: [[nodiscard]] toml::table parse_file(const std::filesystem::path& filepath);

Что делает: Парсит TOML-файл по указанному пути и возвращает корневую таблицу (toml::table). Выбрасывает исключение toml::parse_error при ошибке.

try {
    auto config = toml::parse_file("settings.toml");
    // работаем с config
} catch (const toml::parse_error& err) {
    std::cerr << "Ошибка парсинга: " << err << std::endl;
}

4.2. toml::parse()

Сигнатура: [[nodiscard]] toml::table parse(std::istream& stream, std::string source_name = "unknown source");

Что делает: Парсит TOML-данные из потока (например, std::stringstream или std::ifstream). Полезно для чтения из строки или сети.

std::string toml_content = R"(
    [info]
    name = "Test"
    version = 1
)";
std::stringstream stream(toml_content);
auto config = toml::parse(stream, "string_input");
std::cout << config["info"]["name"] << std::endl; // "Test"

4.3. toml::table::operator[]

Сигнатура: toml::node& operator[](std::string_view key);

Что делает: Получает доступ к узлу (node) по ключу. Если ключ не найден, возвращает специальный узел-пустышку. Поддерживает цепочки: config["table"]["key"].

auto config = toml::parse_file("config.toml");
auto& server_host = config["server"]["host"]; // доступ к узлу
if (server_host) {
    std::cout << server_host.as_string() << std::endl;
}

4.4. toml::node::value_or()

Сигнатура: template<typename T> T value_or(T default_value) const;

Что делает: Безопасно извлекает значение указанного типа. Если узел отсутствует или имеет неверный тип, возвращает значение по умолчанию. Это основной способ чтения данных.

auto config = toml::parse_file("config.toml");
int port = config["server"]["port"].value_or(8080); // если нет, то 8080
std::string host = config["server"]["host"].value_or("localhost");
bool debug = config["server"]["debug"].value_or(false);

4.5. toml::node::as_*() семейство методов

Сигнатура: toml::string& as_string();, toml::integer& as_integer();, toml::boolean& as_boolean();, toml::array& as_array();, toml::table& as_table(); и т.д.

Что делает: Пытается привести узел к конкретному типу. Если тип не совпадает, выбрасывает исключение toml::type_error. Используйте, когда уверены в типе данных.

auto config = toml::parse_file("config.toml");
try {
    auto& arr = config["tags"].as_array();
    for (auto& elem : *arr) {
        std::cout << elem.as_string() << ", ";
    }
} catch (const toml::type_error& e) {
    std::cerr << "Ошибка типа: " << e.what() << std::endl;
}

4.6. toml::table::insert()

Сигнатура: std::pair<toml::node*, bool> insert(std::string_view key, toml::node&& value);

Что делает: Вставляет новую пару ключ-значение в таблицу. Если ключ уже существует, обновляет значение. Возвращает указатель на узел и флаг успеха.

auto config = toml::table{};
config.insert("title", toml::value("My App"));
config.insert("version", toml::value(1));

// Вложенная таблица
auto& server = config["server"].as_table();
server.insert("host", toml::value("0.0.0.0"));

// Сохраняем в файл
std::ofstream file("output.toml");
file << config;

4.7. toml::table::erase()

Сигнатура: bool erase(std::string_view key);

Что делает: Удаляет элемент по ключу. Возвращает true, если элемент был найден и удалён.

auto config = toml::parse_file("config.toml");
if (config.erase("temporary_section")) {
    std::cout << "Секция удалена" << std::endl;
}
// Сохраняем изменения
std::ofstream("config.toml") << config;

4.8. toml::node::is_*() семейство методов

Сигнатура: bool is_string() const;, bool is_integer() const;, bool is_table() const;, bool is_array() const;, bool is_date() const; и т.д.

Что делает: Проверяет тип узла без выбрасывания исключений. Полезно для валидации и ветвления.

auto config = toml::parse_file("config.toml");
for (auto& [key, value] : config) {
    if (value.is_table()) {
        std::cout << key << " является таблицей" << std::endl;
    } else if (value.is_string()) {
        std::cout << key << " = " << value.as_string() << std::endl;
    } else if (value.is_integer()) {
        std::cout << key << " = " << value.as_integer() << std::endl;
    }
}

4.9. toml::node::visit()

Сигнатура: template<typename Visitor> decltype(auto) visit(Visitor&& visitor);

Что делает: Применяет лямбду-визитор к узлу, автоматически вызывая нужную перегрузку в зависимости от типа узла. Мощный инструмент для рекурсивного обхода.

auto config = toml::parse_file("config.toml");
config.visit([](auto&& node) {
    using T = std::decay_t<decltype(node)>;
    if constexpr (toml::is_string<T>) {
        std::cout << "Строка: " << node << std::endl;
    } else if constexpr (toml::is_integer<T>) {
        std::cout << "Целое: " << node << std::endl;
    } else if constexpr (toml::is_table<T>) {
        std::cout << "Таблица с " << node.size() << " элементами" << std::endl;
    }
});

4.10. toml::format_flags и toml::table::format()

Сигнатура: std::string format(const toml::format_flags& flags = {}) const;

Что делает: Форматирует таблицу обратно в

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