Неточный перевод

This commit is contained in:
2025-10-25 16:10:29 +03:00
parent 075635299e
commit dba4d7ee04
5 changed files with 985 additions and 1 deletions

View 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
View 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**:
* Меньше вероятность ошибок при переименовании опций
* Более чистый код
* Автоматическая обработка наличия значения
Такой подход рекомендуется использовать для проверки наличия опций в программе.

View File

@@ -1,2 +1,7 @@
# Оглавление
- [Introducion](introduction.md)
- [Введение](introduction.md)
- [Туториал](tutorial.md)
- [Обзор библиотеки](library_overview.md)
- [How To](how_to.md)
- [Обсуждение дизайна](design_discussion.md)

View 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
View 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
```
В этом примере значения из конфигурационного файла и командной строки корректно объединяются, при этом значения из командной строки имеют приоритет.