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;
Что делает: Форматирует таблицу обратно в
Также в библиотеке
Работа с S3 и облачными хранилищами в TypeScript: библиотеки и примеры
Elasticsearch .NET для C# (.NET): полное руководство с примерами
Compose Multiplatform для Kotlin: полное руководство с примерами