Неточный перевод
This commit is contained in:
77
boost/1.89.0/design_discussion.md
Normal file
77
boost/1.89.0/design_discussion.md
Normal file
@@ -0,0 +1,77 @@
|
||||
## Обсуждение дизайна библиотеки
|
||||
|
||||
### Поддержка Unicode
|
||||
|
||||
**Unicode-поддержка** в библиотеке означает:
|
||||
* Возможность парсинга как char*, так и wchar_t*
|
||||
* Возможность указания типа обработки для каждой опции (ASCII или Unicode)
|
||||
* Гарантии корректной конвертации данных
|
||||
|
||||
### Основные гарантии библиотеки
|
||||
|
||||
* ASCII-вход передается в ASCII-значение без изменений
|
||||
* Unicode-вход передается в Unicode-значение без изменений
|
||||
* При несовпадении типов происходит автоматическая конвертация через codecvt
|
||||
|
||||
### Особенности реализации
|
||||
|
||||
**Смешанная поддержка** ASCII и Unicode:
|
||||
* Возможность использования обоих типов опций одновременно
|
||||
* Отсутствие необходимости писать дополнительный код для Unicode
|
||||
* Совместимость с существующими библиотеками
|
||||
|
||||
### Проблемы реализации
|
||||
|
||||
**Основные сложности**:
|
||||
* Сравнение Unicode-строк
|
||||
* Интернационализация имен опций
|
||||
* Необходимость дополнительных настроек для корректной работы
|
||||
|
||||
### Подход к реализации
|
||||
|
||||
**Варианты реализации**:
|
||||
1. Шаблонное решение с std::basic_string
|
||||
2. Внутренняя кодировка с конвертацией на границах
|
||||
|
||||
**Выбранный подход**:
|
||||
* Использование внутренней кодировки UTF-8
|
||||
* Конвертация только при необходимости
|
||||
* Минимизация накладных расходов
|
||||
|
||||
### Компоненты системы
|
||||
|
||||
**Парсеры**:
|
||||
* Работа с входными строками
|
||||
* Конвертация в internal encoding
|
||||
* Хранение результатов в parsed_options
|
||||
|
||||
**Описания опций**:
|
||||
* Поддержка смешанных типов
|
||||
* Дополнительная информация о кодировке
|
||||
* Гибкая обработка значений
|
||||
|
||||
**Хранение данных**:
|
||||
* Конвертация при сохранении
|
||||
* Информирование о типе кодировки
|
||||
* Корректная работа с разными типами
|
||||
|
||||
### Выбор внутренней кодировки
|
||||
|
||||
**Критерии выбора**:
|
||||
* Скорость обработки
|
||||
* Затраты памяти
|
||||
* Размер кода
|
||||
|
||||
**Принятое решение**: UTF-8 как внутренняя кодировка из-за:
|
||||
* Универсальности
|
||||
* Эффективности для ASCII-данных
|
||||
* Простоты интеграции с существующими компонентами
|
||||
|
||||
### Особые случаи
|
||||
|
||||
**Важные моменты**:
|
||||
* Предполагается ASCII-кодировка для символьных литералов
|
||||
* Учет возможных проблем с комбинирующими символами
|
||||
* Практическая нерелевантность проблем в большинстве случаев
|
||||
|
||||
Такой подход обеспечивает баланс между функциональностью, производительностью и простотой использования библиотеки.
|
||||
333
boost/1.89.0/how_to.md
Normal file
333
boost/1.89.0/how_to.md
Normal file
@@ -0,0 +1,333 @@
|
||||
## Нестандартные случаи использования библиотеки
|
||||
|
||||
### Нестандартный синтаксис
|
||||
|
||||
Иногда требуется поддержка нестандартного синтаксиса командных строк. Например, как в компиляторе gcc с опциями `-frtti` и `-fno-rtti`.
|
||||
|
||||
Для таких случаев библиотека позволяет предоставить дополнительный парсер — функцию, которая вызывается для каждого элемента командной строки.
|
||||
|
||||
Пример реализации:
|
||||
```cpp
|
||||
pair<string, string> reg_foo(const string& s) {
|
||||
if (s.find("-f") == 0) {
|
||||
if (s.substr(2, 3) == "no-")
|
||||
return make_pair(s.substr(5), string("false"));
|
||||
else
|
||||
return make_pair(s.substr(2), string("true"));
|
||||
} else {
|
||||
return make_pair(string(), string());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Использование дополнительного парсера:
|
||||
```cpp
|
||||
store(command_line_parser(ac, av)
|
||||
.options(desc)
|
||||
.extra_parser(reg_foo)
|
||||
.run(), vm);
|
||||
```
|
||||
|
||||
### Файлы ответов (Response Files)
|
||||
|
||||
Для обхода ограничений длины командной строки используются файлы ответов.
|
||||
|
||||
Шаги реализации:
|
||||
|
||||
1. Определение опции для файла ответов:
|
||||
```cpp
|
||||
("response-file", value<string>(), "can be specified with '@name', too")
|
||||
```
|
||||
|
||||
2. Дополнительный парсер для синтаксиса `@file`:
|
||||
```cpp
|
||||
pair<string, string> at_option_parser(string const&s) {
|
||||
if ('@' == s[0])
|
||||
return make_pair(string("response-file"), s.substr(1));
|
||||
else
|
||||
return make_pair(string(), string());
|
||||
}
|
||||
```
|
||||
|
||||
3. Обработка найденного файла ответов:
|
||||
```cpp
|
||||
if (vm.count("response-file")) {
|
||||
ifstream ifs(vm["response-file"].as<string>().c_str());
|
||||
if (!ifs) {
|
||||
cout << "Could not open the response file\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
stringstream ss;
|
||||
ss << ifs.rdbuf();
|
||||
|
||||
char_separator<char> sep(" \n\r");
|
||||
string ResponsefileContents(ss.str());
|
||||
tokenizer<char_separator<char>> tok(ResponsefileContents, sep);
|
||||
|
||||
vector<string> args;
|
||||
copy(tok.begin(), tok.end(), back_inserter(args));
|
||||
|
||||
store(command_line_parser(args).options(desc).run(), vm);
|
||||
}
|
||||
```
|
||||
|
||||
### Другие возможности
|
||||
|
||||
* **Winmain Command Line** — поддержка специфичного синтаксиса Windows
|
||||
* **Группы опций и скрытые опции** — организация опций в логические группы
|
||||
* **Пользовательские валидаторы** — создание собственных правил проверки значений
|
||||
* **Поддержка Unicode** — работа с Unicode-строками
|
||||
* **Неизвестные опции** — возможность разрешать неизвестные опции
|
||||
* **Проверка наличия опций** — механизмы проверки присутствия опций
|
||||
|
||||
Эти возможности позволяют гибко настраивать поведение библиотеки под конкретные требования проекта.
|
||||
|
||||
|
||||
## Работа с командной строкой в Windows
|
||||
|
||||
### Особенности Winmain
|
||||
|
||||
В Windows GUI-приложения получают командную строку как единую строку, а не как массив элементов. Для решения этой проблемы библиотека предоставляет функцию **split_winmain**.
|
||||
|
||||
Пример использования:
|
||||
```cpp
|
||||
vector<string> args = split_winmain(lpCmdLine);
|
||||
store(command_line_parser(args).options(desc).run(), vm);
|
||||
```
|
||||
|
||||
Функция **split_winmain** имеет перегрузку для строк **wchar_t**, что позволяет использовать её в Unicode-приложениях.
|
||||
|
||||
## Группы опций и скрытые опции
|
||||
|
||||
### Проблемы единого описания опций
|
||||
|
||||
При использовании единого экземпляра **options_description** возникают сложности:
|
||||
* Некоторые опции имеют смысл только для определённых источников
|
||||
* Требуется структурированная справка
|
||||
* Некоторые опции не должны отображаться в справке
|
||||
|
||||
### Решение через группы опций
|
||||
|
||||
Библиотека позволяет создавать несколько экземпляров **options_description** и объединять их по необходимости.
|
||||
|
||||
Пример группировки:
|
||||
|
||||
```cpp
|
||||
// Общая группа опций
|
||||
options_description general("Общие опции");
|
||||
general.add_options()
|
||||
("help", "показать справку")
|
||||
("help-module", value<string>(), "показать справку по модулю")
|
||||
("version", "показать версию");
|
||||
|
||||
// Группа опций GUI
|
||||
options_description gui("Опции GUI");
|
||||
gui.add_options()
|
||||
("display", value<string>(), "используемый дисплей");
|
||||
|
||||
// Группа опций бэкенда
|
||||
options_description backend("Опции бэкенда");
|
||||
backend.add_options()
|
||||
("num-threads", value<int>(), "начальное число потоков");
|
||||
```
|
||||
|
||||
### Объединение групп
|
||||
|
||||
Создаём два объединения:
|
||||
* Полное для парсинга
|
||||
* Видимое для справки
|
||||
|
||||
```cpp
|
||||
// Все опции для парсинга
|
||||
options_description all("Разрешённые опции");
|
||||
all.add(general).add(gui).add(backend);
|
||||
|
||||
// Видимые опции для справки
|
||||
options_description visible("Разрешённые опции");
|
||||
visible.add(general).add(gui);
|
||||
```
|
||||
|
||||
### Обработка опций
|
||||
|
||||
```cpp
|
||||
variables_map vm;
|
||||
store(parse_command_line(ac, av, all), vm);
|
||||
|
||||
if (vm.count("help")) {
|
||||
cout << visible;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vm.count("help-module")) {
|
||||
const string& s = vm["help-module"].as<string>();
|
||||
if (s == "gui") {
|
||||
cout << gui;
|
||||
} else if (s == "backend") {
|
||||
cout << backend;
|
||||
} else {
|
||||
cout << "Неизвестный модуль '" << s << "'\n";
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Такой подход позволяет:
|
||||
* Структурировать опции по группам
|
||||
* Контролировать видимость опций в справке
|
||||
* Гибко настраивать поведение программы
|
||||
|
||||
|
||||
## Пользовательские валидаторы
|
||||
|
||||
### Настройка конвертации значений
|
||||
|
||||
По умолчанию конвертация значений опций выполняется через iostreams. Библиотека позволяет настроить собственную конвертацию для конкретных классов.
|
||||
|
||||
Пример создания пользовательского валидатора:
|
||||
|
||||
```cpp
|
||||
struct magic_number {
|
||||
public:
|
||||
magic_number(int n) : n(n) {}
|
||||
int n;
|
||||
};
|
||||
|
||||
void validate(boost::any& v,
|
||||
const std::vector<std::string>& values,
|
||||
magic_number* target_type, int)
|
||||
{
|
||||
static regex r("\\d\\d\\d-(\\d\\d\\d)");
|
||||
using namespace boost::program_options;
|
||||
|
||||
// Проверка на множественные присваивания
|
||||
validators::check_first_occurrence(v);
|
||||
|
||||
// Получение единственной строки
|
||||
const string& s = validators::get_single_string(values);
|
||||
|
||||
// Проверка через регулярное выражение
|
||||
smatch match;
|
||||
if (regex_match(s, match, r)) {
|
||||
v = any(magic_number(lexical_cast<int>(match[1])));
|
||||
} else {
|
||||
throw validation_error(validation_error::invalid_option_value);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Параметры функции валидации:
|
||||
* **v** — хранилище для значения
|
||||
* **values** — список строк
|
||||
* **target_type** — указатель на целевой тип
|
||||
* Дополнительный параметр для совместимости с компиляторами
|
||||
|
||||
### Поддержка Unicode
|
||||
|
||||
Для работы с Unicode необходимо:
|
||||
* Использовать Unicode-совместимые парсеры
|
||||
* Указывать поддержку Unicode для нужных опций
|
||||
|
||||
Особенности работы:
|
||||
* Большинство парсеров имеют Unicode-версии
|
||||
* Для создания Unicode-опций используется **wvalue** вместо **value**
|
||||
* Автоматическое преобразование кодировок между Unicode и локальными
|
||||
|
||||
### Настройка локализаций
|
||||
|
||||
Для корректной работы с Unicode:
|
||||
```cpp
|
||||
locale::global(locale("")); // Настройка конвертации согласно локали пользователя
|
||||
```
|
||||
|
||||
### Тестирование поддержки локализаций
|
||||
|
||||
Проверка включает:
|
||||
1. Сборка теста **test_convert**
|
||||
2. Установка не-ASCII локали:
|
||||
```bash
|
||||
export LC_CTYPE=ru_RU.KOI8-R
|
||||
```
|
||||
3. Запуск теста с не-ASCII строкой
|
||||
|
||||
При успешной работе вы увидите список Unicode-кодов, что подтверждает корректную поддержку локализаций.
|
||||
|
||||
Такой подход позволяет:
|
||||
* Настраивать собственную логику валидации
|
||||
* Работать с Unicode-данными
|
||||
* Обеспечивать корректную конвертацию кодировок
|
||||
|
||||
## Разрешение неизвестных опций
|
||||
|
||||
### Стандартное поведение
|
||||
|
||||
По умолчанию библиотека генерирует исключение при обнаружении неизвестных опций. Однако это поведение можно изменить.
|
||||
|
||||
### Разрешение неизвестных опций
|
||||
|
||||
Для разрешения неизвестных опций:
|
||||
1. Используйте **basic_command_line_parser** вместо **parse_command_line**
|
||||
2. Вызовите метод **allow_unregistered**
|
||||
|
||||
Пример:
|
||||
```cpp
|
||||
parsed_options parsed = command_line_parser(argc, argv)
|
||||
.options(desc)
|
||||
.allow_unregistered()
|
||||
.run();
|
||||
```
|
||||
|
||||
При обнаружении неизвестной опции создается объект **basic_option** с полями:
|
||||
* **string_key** — имя опции
|
||||
* **value** — значение опции
|
||||
* **unregistered** — флаг неизвестной опции
|
||||
* **original_tokens** — исходные токены
|
||||
|
||||
### Передача неизвестных опций
|
||||
|
||||
Для сбора неизвестных опций используйте функцию **collect_unrecognized**:
|
||||
```cpp
|
||||
vector<string> to_pass_further = collect_unrecognized(
|
||||
parsed.options,
|
||||
include_positional
|
||||
);
|
||||
```
|
||||
|
||||
## Проверка наличия опций
|
||||
|
||||
### Традиционный подход
|
||||
|
||||
Ранее проверка осуществлялась через метод **count**:
|
||||
```cpp
|
||||
if (vm.count("compression")) {
|
||||
cout << "Уровень сжатия установлен: " << vm["compression"].as<int>() << endl;
|
||||
}
|
||||
```
|
||||
|
||||
### Улучшенный подход с boost::optional
|
||||
|
||||
Использование **boost::optional** позволяет:
|
||||
* Автоматически инициализировать переменную при наличии опции
|
||||
* Упростить проверку наличия опции
|
||||
|
||||
Пример:
|
||||
```cpp
|
||||
boost::optional<int> compression;
|
||||
desc.add_options()
|
||||
("compression", po::value(&compression), "уровень сжатия");
|
||||
|
||||
// После парсинга и уведомления
|
||||
if (compression) {
|
||||
cout << "Уровень сжатия установлен: " << *compression << endl;
|
||||
} else {
|
||||
cout << "Уровень сжатия не установлен" << endl;
|
||||
}
|
||||
```
|
||||
|
||||
Преимущества подхода с **boost::optional**:
|
||||
* Меньше вероятность ошибок при переименовании опций
|
||||
* Более чистый код
|
||||
* Автоматическая обработка наличия значения
|
||||
|
||||
Такой подход рекомендуется использовать для проверки наличия опций в программе.
|
||||
@@ -1,2 +1,7 @@
|
||||
# Оглавление
|
||||
|
||||
- [Introducion](introduction.md)
|
||||
- [Введение](introduction.md)
|
||||
- [Туториал](tutorial.md)
|
||||
- [Обзор библиотеки](library_overview.md)
|
||||
- [How To](how_to.md)
|
||||
- [Обсуждение дизайна](design_discussion.md)
|
||||
|
||||
451
boost/1.89.0/library_overview.md
Normal file
451
boost/1.89.0/library_overview.md
Normal file
@@ -0,0 +1,451 @@
|
||||
## Общая архитектура библиотеки program_options
|
||||
|
||||
### Основные компоненты библиотеки
|
||||
|
||||
Библиотека состоит из трёх главных компонентов:
|
||||
|
||||
* **Компонент описания опций** — определяет допустимые параметры и действия с их значениями
|
||||
* **Компонент парсеров** — использует эту информацию для поиска имён параметров и их значений в источниках ввода
|
||||
* **Компонент хранения** — предоставляет интерфейс для доступа к значениям параметров и преобразует строковые представления в нужные типы C++
|
||||
|
||||
### Ключевые классы и функции
|
||||
|
||||
* Класс **options_description** относится к компоненту описания опций
|
||||
* Функция **parse_command_line** является частью компонента парсеров
|
||||
* Класс **variables_map** принадлежит компоненту хранения
|
||||
|
||||
### Взаимодействие компонентов
|
||||
|
||||
В предыдущих примерах мы видели, как эти компоненты используются в функции main для парсинга командной строки и конфигурационных файлов. Рассмотрим теперь особенности работы вне функции main.
|
||||
|
||||
### Архитектура программы
|
||||
|
||||
Для частей программы, находящихся вне main, наиболее важен **компонент хранения**. Он предоставляет класс, хранящий все значения параметров, который можно свободно передавать между модулями программы.
|
||||
|
||||
Важные особенности:
|
||||
* Остальные компоненты используются только там, где выполняется парсинг
|
||||
* Отдельные модули программы могут описывать свои параметры и передавать их в основной модуль
|
||||
* Основной модуль может объединять все описания параметров
|
||||
* Такой подход особенно полезен при большом количестве параметров
|
||||
|
||||
### Рекомендации по использованию
|
||||
|
||||
При разработке крупных приложений рекомендуется:
|
||||
* Централизовать описание параметров в одном месте
|
||||
* Использовать модульный подход при большом количестве опций
|
||||
* Передавать объект хранения между компонентами программы
|
||||
* Обеспечивать корректную обработку параметров во всех модулях
|
||||
|
||||
|
||||
## Компонент описания опций
|
||||
|
||||
### Основные классы компонента
|
||||
|
||||
Компонент описания опций включает три ключевых класса:
|
||||
|
||||
* **option_description** — содержит имя опции, описание и указатель на value_semantic
|
||||
* **value_semantic** — знает тип значения опции, может парсить значение, применять значение по умолчанию
|
||||
* **options_description** — контейнер для экземпляров option_description
|
||||
|
||||
### Синтаксическое и семантическое описание
|
||||
|
||||
#### Синтаксическая информация
|
||||
Включает:
|
||||
* Имя опции
|
||||
* Количество токенов для указания значения
|
||||
* Используется парсерами для группировки токенов в пары (имя, значение)
|
||||
|
||||
#### Семантическая информация
|
||||
Отвечает за:
|
||||
* Преобразование значений в типы C++
|
||||
* Валидацию данных
|
||||
* Применение значений по умолчанию
|
||||
|
||||
### Практическое применение
|
||||
|
||||
Пример объявления опций:
|
||||
```cpp
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("help", "показать справку")
|
||||
("optimization", value<int>()->default_value(10), "уровень оптимизации")
|
||||
;
|
||||
```
|
||||
|
||||
### Механизм работы
|
||||
|
||||
* Функция **value** создаёт экземпляр класса **typed_value**
|
||||
* **typed_value** — производный класс от **value_semantic**
|
||||
* Содержит код для парсинга значений определённого типа
|
||||
* Поддерживает методы для указания дополнительной информации
|
||||
|
||||
### Дополнительные возможности
|
||||
|
||||
Библиотека предоставляет:
|
||||
* Функцию **bool_switch** для булевых значений
|
||||
* Возможность создания пользовательских подклассов **value_semantic**
|
||||
|
||||
### Важные аспекты проектирования
|
||||
|
||||
Разделение на синтаксический и семантический уровни:
|
||||
* Парсеры работают только с синтаксическим уровнем
|
||||
* Ограничивает использование чрезмерно сложных структур
|
||||
* Пример проблемы:
|
||||
```bash
|
||||
calc --expression=1 + 2/3 # сложно парсить без контекста
|
||||
```
|
||||
* Решённая версия:
|
||||
```bash
|
||||
calc --expression="1 + 2/3" # синтаксис ясен
|
||||
```
|
||||
|
||||
Такое разделение является ключевым элементом дизайна библиотеки, обеспечивая чёткое разделение ответственности между компонентами.
|
||||
|
||||
|
||||
## Синтаксическая информация опций
|
||||
|
||||
### Основные компоненты
|
||||
|
||||
Синтаксическая информация предоставляется классами **boost::program_options::options_description** и методами **boost::program_options::value_semantic**. Она включает:
|
||||
|
||||
* **Имя опции** — используется для идентификации внутри программы
|
||||
* **Описание опции** — отображается пользователю
|
||||
* **Количество токенов** — определяет, сколько элементов может содержать значение опции при парсинге
|
||||
|
||||
### Примеры использования
|
||||
|
||||
Рассмотрим практический пример объявления опций:
|
||||
|
||||
```cpp
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("help", "показать справочное сообщение")
|
||||
("compression", value<string>(), "уровень сжатия")
|
||||
("verbose", value<string>()->implicit_value("0"), "уровень детализации")
|
||||
("email", value<string>()->multitoken(), "email для отправки")
|
||||
;
|
||||
```
|
||||
|
||||
Особенности каждой опции:
|
||||
* Первая опция (`help`) не требует значения
|
||||
* Вторая опция (`compression`) требует ровно один токен значения
|
||||
* Третья опция (`verbose`) может принимать либо один токен, либо не принимать значение вообще
|
||||
* Четвёртая опция (`email`) может принимать несколько токенов
|
||||
|
||||
### Пример командной строки
|
||||
|
||||
Допустимый вариант использования опций:
|
||||
|
||||
```bash
|
||||
test --help --compression 10 --verbose --email beadle@mars beadle2@mars
|
||||
```
|
||||
|
||||
### Важные характеристики
|
||||
|
||||
* **Неявные значения** (implicit_value) позволяют опции иметь значение по умолчанию при отсутствии явного указания
|
||||
* **Многокомпонентные значения** (multitoken) позволяют опции принимать несколько токенов
|
||||
* Каждая опция может иметь собственное правило обработки значений
|
||||
|
||||
Такой подход обеспечивает гибкость при определении правил обработки параметров командной строки и конфигурационных файлов.
|
||||
|
||||
## Форматирование описаний опций
|
||||
|
||||
### Базовое форматирование
|
||||
|
||||
Описания опций могут быть достаточно объёмными, особенно когда требуется документировать несколько значений. Библиотека предоставляет простые механизмы форматирования.
|
||||
|
||||
### Структура описания
|
||||
|
||||
* Описание состоит из одного или нескольких параграфов, разделённых символом новой строки (`\n`)
|
||||
* При выводе библиотека автоматически вычисляет отступы для описания опции
|
||||
* Каждый параграф выводится как отдельная строка с рассчитанным отступом
|
||||
* Если параграф не помещается в одну строку, он переносится на несколько строк с одинаковым отступом
|
||||
|
||||
### Управление отступами
|
||||
|
||||
#### Базовый отступ
|
||||
|
||||
Можно задать дополнительный отступ для первой строки, добавив пробелы в начале параграфа:
|
||||
|
||||
```cpp
|
||||
options.add_options()
|
||||
("help", " Подробное описание опции, которое может быть очень длинным и занимать несколько строк")
|
||||
;
|
||||
```
|
||||
|
||||
Результат будет выглядеть так:
|
||||
```
|
||||
--help Подробное описание опции, которое может быть
|
||||
очень длинным и занимать несколько строк
|
||||
```
|
||||
|
||||
### Расширенное форматирование
|
||||
|
||||
Для более сложного форматирования можно использовать символ табуляции (`\t`):
|
||||
|
||||
```cpp
|
||||
options.add_options()
|
||||
("well_formated", "Описание опции:\n"
|
||||
"\n"
|
||||
"Значения:\n"
|
||||
" Значение1:\tОписание первого значения, которое может быть длинным\n"
|
||||
" Значение2:\tОписание второго значения\n"
|
||||
"\n"
|
||||
" Этот параграф имеет отступ только для первой строки");
|
||||
```
|
||||
|
||||
Результат:
|
||||
```
|
||||
--well_formated Описание опции:
|
||||
|
||||
Значения:
|
||||
Значение1: Описание первого значения, которое может быть
|
||||
длинным
|
||||
Значение2: Описание второго значения
|
||||
|
||||
Этот параграф имеет отступ только для первой строки
|
||||
```
|
||||
|
||||
### Важные ограничения
|
||||
|
||||
* Символ табуляции удаляется перед выводом
|
||||
* Разрешён только один символ табуляции на параграф
|
||||
* При нарушении этого правила выбрасывается исключение типа `program_options::error`
|
||||
* Табуляция игнорируется, если:
|
||||
* Она находится не в первой строке параграфа
|
||||
* Она расположена в последней возможной позиции первой строки
|
||||
|
||||
|
||||
## Семантическая информация и парсеры
|
||||
|
||||
### Семантическая информация
|
||||
|
||||
Семантическая информация полностью предоставляется классом **boost::program_options::value_semantic**. Рассмотрим пример:
|
||||
|
||||
```cpp
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("compression", value<int>()->default_value(10), "уровень сжатия")
|
||||
("email", value<vector<string>>()
|
||||
->composing()->notifier(&your_function), "email")
|
||||
;
|
||||
```
|
||||
|
||||
Этот код определяет:
|
||||
* Значение по умолчанию для первой опции — 10
|
||||
* Вторая опция может появляться несколько раз, и все значения будут объединены
|
||||
* После парсинга будет вызвана функция `your_function` с значением опции "email"
|
||||
|
||||
### Позиционные опции
|
||||
|
||||
**Позиционные опции** — это элементы командной строки без явного указания имени опции. Например:
|
||||
```bash
|
||||
archiver --compression=9 /etc/passwd
|
||||
```
|
||||
|
||||
Здесь `/etc/passwd` — позиционная опция.
|
||||
|
||||
Для обработки таких опций используется класс **positional_options_description**:
|
||||
|
||||
```cpp
|
||||
positional_options_description pd;
|
||||
pd.add("input-file", 1); // Первая позиционная опция будет иметь имя "input-file"
|
||||
```
|
||||
|
||||
Можно задать несколько позиционных опций:
|
||||
```cpp
|
||||
positional_options_description pd;
|
||||
pd.add("output-file", 2).add("input-file", -1);
|
||||
```
|
||||
|
||||
В этом примере:
|
||||
* Первые две позиционные опции получат имя "output-file"
|
||||
* Все последующие — имя "input-file"
|
||||
|
||||
**Важное замечание**: класс **positional_options_description** только определяет соответствие позиции имени, само имя должно быть зарегистрировано в экземпляре **options_description**.
|
||||
|
||||
### Компонент парсеров
|
||||
|
||||
**Компонент парсеров** выполняет следующие функции:
|
||||
* Разбивает входные данные на пары (имя, значение)
|
||||
* Проверяет, известны ли опции
|
||||
* Определяет способ указания значений
|
||||
|
||||
Процесс парсинга:
|
||||
1. Парсер ищет возможные опции
|
||||
2. Сверяется с описанием опций
|
||||
3. Определяет, известно ли имя опции
|
||||
4. Использует **value_semantic** для обработки значений
|
||||
|
||||
### Особенности парсинга
|
||||
|
||||
Три важных исключения из стандартной модели:
|
||||
|
||||
1. **Короткие имена опций**:
|
||||
* Можно использовать сокращённые имена
|
||||
* Поддерживается автоматическое определение по префиксам
|
||||
|
||||
2. **Многокомпонентные значения**:
|
||||
* Опция может принимать несколько токенов
|
||||
* Требует явного включения
|
||||
|
||||
3. **Позиционные опции**:
|
||||
* Механизм автоматического определения имён
|
||||
* Гибкая настройка через **positional_options_description**
|
||||
|
||||
### Использование парсеров
|
||||
|
||||
Для запуска парсера обычно вызывается функция с параметрами:
|
||||
* Описание опций
|
||||
* Источник данных (командная строка, конфигурационный файл)
|
||||
|
||||
Результаты парсинга возвращаются в виде объекта класса **parsed_options**, который передаётся компоненту хранения.
|
||||
|
||||
|
||||
## Компонент хранения
|
||||
|
||||
### Основные функции
|
||||
|
||||
Компонент хранения отвечает за:
|
||||
* Хранение конечных значений опций в специальном классе и обычных переменных
|
||||
* Управление приоритетами между различными источниками
|
||||
* Вызов пользовательских функций уведомления с финальными значениями опций
|
||||
|
||||
### Пример использования
|
||||
|
||||
```cpp
|
||||
variables_map vm;
|
||||
store(parse_command_line(argc, argv, desc), vm);
|
||||
store(parse_config_file("example.cfg", desc), vm);
|
||||
notify(vm);
|
||||
```
|
||||
|
||||
### Особенности работы
|
||||
|
||||
* Класс **variables_map** используется для хранения значений опций
|
||||
* Функция **store** добавляет значения из различных источников
|
||||
* Функция **notify** запускает пользовательские обработчики и сохраняет значения в обычные переменные
|
||||
* Приоритет определяется порядком обработки: если значение уже установлено, оно не перезаписывается
|
||||
|
||||
### Важное предупреждение
|
||||
|
||||
**Не забудьте** вызвать функцию **notify** после сохранения всех проанализированных значений!
|
||||
|
||||
## Парсеры конфигурационных файлов
|
||||
|
||||
### Синтаксис конфигурационных файлов
|
||||
|
||||
Файлы конфигурации имеют простой INI-подобный формат:
|
||||
|
||||
* Строка вида `name=value` задаёт значение опции
|
||||
* Секция начинается со строки `[section name]`
|
||||
* Символ `#` начинает комментарий до конца строки
|
||||
|
||||
### Иерархия опций
|
||||
|
||||
Имена опций относительны к именам секций. Например:
|
||||
|
||||
```ini
|
||||
[gui.accessibility]
|
||||
visual_bell=yes
|
||||
```
|
||||
|
||||
эквивалентно:
|
||||
|
||||
```ini
|
||||
gui.accessibility.visual_bell=yes
|
||||
```
|
||||
|
||||
### Пример описания опции
|
||||
|
||||
```cpp
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("gui.accessibility.visual_bell", value<string>(), "визуальный звонок")
|
||||
;
|
||||
```
|
||||
|
||||
### Парсер переменных окружения
|
||||
|
||||
Библиотека также поддерживает парсинг переменных окружения, что позволяет:
|
||||
* Использовать значения из окружения системы
|
||||
* Объединять их с другими источниками конфигурации
|
||||
* Управлять поведением программы через системные переменные
|
||||
|
||||
Такой подход обеспечивает гибкую систему конфигурации приложения с возможностью комбинирования различных источников настроек.
|
||||
|
||||
|
||||
## Парсер переменных окружения
|
||||
|
||||
### Что такое переменные окружения
|
||||
|
||||
**Переменные окружения** — это строковые переменные, доступные всем программам через функцию `getenv` стандартной библиотеки C. Их можно установить:
|
||||
* Для всей системы
|
||||
* Для конкретного пользователя
|
||||
* Через командную строку
|
||||
|
||||
### Использование парсера
|
||||
|
||||
Функция **parse_environment** позволяет парсить переменные окружения. У неё есть несколько перегруженных версий. Первый параметр — экземпляр **options_description**, второй определяет, какие переменные обрабатывать.
|
||||
|
||||
### Соглашения об именовании
|
||||
|
||||
Для избежания конфликтов имён рекомендуется:
|
||||
* Использовать уникальный префикс для переменных окружения
|
||||
* Использовать верхний регистр для имён переменных
|
||||
* Преобразовывать имена опций в нижний регистр
|
||||
|
||||
Пример:
|
||||
* Опция: `proxy`
|
||||
* Переменная окружения: `BOOST_PROXY`
|
||||
|
||||
### Настройка парсинга
|
||||
|
||||
При вызове **parse_environment** можно указать:
|
||||
* Префикс для фильтрации переменных
|
||||
* Функцию преобразования имён (принимает `std::string` и возвращает `std::string`)
|
||||
|
||||
### Преобразование типов
|
||||
|
||||
Все значения из командной строки, переменных окружения и конфигурационных файлов изначально являются строками. Библиотека автоматически преобразует их в нужные типы.
|
||||
|
||||
#### Числовые типы
|
||||
|
||||
Преобразование выполняется через **lexical_cast**:
|
||||
* Поддерживаются целые числа: `41`, `-42`
|
||||
* Поддерживаются числа с плавающей точкой: `51.1`, `-52.1`, `53.1234567890`
|
||||
* Поддерживаются экспоненциальные записи: `57.1e5`, `58.1E5`
|
||||
|
||||
#### Булевы значения
|
||||
|
||||
Есть два способа работы с булевыми значениями:
|
||||
|
||||
1. Через явное указание:
|
||||
```bash
|
||||
example --my-option=true
|
||||
```
|
||||
|
||||
2. Через переключатель:
|
||||
```bash
|
||||
example --other-switch
|
||||
```
|
||||
|
||||
Значения, интерпретируемые как true:
|
||||
* `true`
|
||||
* `yes`
|
||||
* `on`
|
||||
* `1`
|
||||
|
||||
Значения, интерпретируемые как false:
|
||||
* `false`
|
||||
* `no`
|
||||
* `off`
|
||||
* `0`
|
||||
|
||||
В конфигурационных файлах опция с именем и знаком равенства без значения также интерпретируется как true.
|
||||
|
||||
### Важные замечания
|
||||
|
||||
* Шестнадцатеричные, восьмеричные и двоичные представления не поддерживаются
|
||||
* Преобразование типов выполняется автоматически при обращении к значениям
|
||||
* Рекомендуется явно указывать ожидаемый тип при описании опций
|
||||
118
boost/1.89.0/tutorial.md
Normal file
118
boost/1.89.0/tutorial.md
Normal file
@@ -0,0 +1,118 @@
|
||||
## Основные сценарии использования библиотеки program_options
|
||||
|
||||
### Начало работы
|
||||
|
||||
В этом разделе мы рассмотрим простейший пример использования библиотеки. Предполагается, что действует следующий алиас пространства имён:
|
||||
|
||||
```cpp
|
||||
namespace po = boost::program_options;
|
||||
```
|
||||
|
||||
#### Пример базового использования
|
||||
|
||||
Простейший пример, обрабатывающий два параметра:
|
||||
|
||||
```cpp
|
||||
// Объявление поддерживаемых параметров
|
||||
po::options_description desc("Допустимые параметры");
|
||||
desc.add_options()
|
||||
("help", "показать справочную информацию")
|
||||
("compression", po::value<int>(), "установить уровень сжатия");
|
||||
|
||||
po::variables_map vm;
|
||||
po::store(po::parse_command_line(ac, av, desc), vm);
|
||||
po::notify(vm);
|
||||
|
||||
if (vm.count("help")) {
|
||||
cout << desc << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (vm.count("compression")) {
|
||||
cout << "Уровень сжатия установлен на "
|
||||
<< vm["compression"].as<int>() << ".\n";
|
||||
} else {
|
||||
cout << "Уровень сжатия не установлен.\n";
|
||||
}
|
||||
```
|
||||
|
||||
### Детали работы с параметрами
|
||||
|
||||
#### Типы и свойства параметров
|
||||
|
||||
Рассмотрим более сложный пример на основе компилятора:
|
||||
|
||||
```cpp
|
||||
int opt;
|
||||
po::options_description desc("Допустимые параметры");
|
||||
desc.add_options()
|
||||
("help", "показать справочную информацию")
|
||||
("optimization", po::value<int>(&opt)->default_value(10), "уровень оптимизации")
|
||||
("include-path,I", po::value<vector<string>>(), "путь включения")
|
||||
("input-file", po::value<vector<string>>(), "входной файл");
|
||||
```
|
||||
|
||||
Особенности этого примера:
|
||||
* Параметр `optimization` имеет значение по умолчанию 10
|
||||
* Параметр `include-path` поддерживает короткое имя `-I`
|
||||
* Векторные типы позволяют указывать параметр несколько раз
|
||||
|
||||
#### Позиционные параметры
|
||||
|
||||
```cpp
|
||||
po::positional_options_description p;
|
||||
p.add("input-file", -1);
|
||||
|
||||
po::variables_map vm;
|
||||
po::store(po::command_line_parser(ac, av)
|
||||
.options(desc).positional(p).run(), vm);
|
||||
po::notify(vm);
|
||||
```
|
||||
|
||||
### Использование нескольких источников
|
||||
|
||||
#### Группировка параметров
|
||||
|
||||
```cpp
|
||||
// Общие параметры командной строки
|
||||
po::options_description generic("Общие параметры");
|
||||
generic.add_options()
|
||||
("version,v", "показать версию")
|
||||
("help", "показать справку");
|
||||
|
||||
// Параметры конфигурации
|
||||
po::options_description config("Конфигурация");
|
||||
config.add_options()
|
||||
("optimization", po::value<int>(&opt)->default_value(10), "уровень оптимизации")
|
||||
("include-path,I", po::value<vector<string>>()->composing(), "путь включения");
|
||||
|
||||
// Скрытые параметры
|
||||
po::options_description hidden("Скрытые параметры");
|
||||
hidden.add_options()
|
||||
("input-file", po::value<vector<string>>(), "входной файл");
|
||||
```
|
||||
|
||||
Пример использования:
|
||||
```bash
|
||||
$ bin/gcc/debug/multiple_sources
|
||||
Пути включения: /opt
|
||||
Уровень оптимизации: 1
|
||||
|
||||
$ bin/gcc/debug/multiple_sources --help
|
||||
Допустимые параметры:
|
||||
|
||||
Общие параметры:
|
||||
-v [ --версия ] : показать версию
|
||||
--help : показать справку
|
||||
|
||||
Конфигурация:
|
||||
--оптимизация n : уровень оптимизации
|
||||
-I [ --путь-включения ] путь : путь включения
|
||||
|
||||
$ bin/gcc/debug/multiple_sources --оптимизация=4 -I foo a.cpp b.cpp
|
||||
Пути включения: foo /opt
|
||||
Входные файлы: a.cpp b.cpp
|
||||
Уровень оптимизации: 4
|
||||
```
|
||||
|
||||
В этом примере значения из конфигурационного файла и командной строки корректно объединяются, при этом значения из командной строки имеют приоритет.
|
||||
Reference in New Issue
Block a user