Он слишком велик, чтобы включить его в ответ о переполнении стека, но я создал библиотеку для декларативного определения командных строк.Он использует возможность C ++ 14 для создания конструктора класса, присваивая начальные значения каждой переменной-члену.
Библиотека в основном является базовым классом.Чтобы определить синтаксис вашей команды, вы объявляете структуру, производную от нее.Вот пример:
struct MyCommandLine : public core::CommandLine {
Argument<std::string> m_verb{this, "program", "program.exe",
"this is what my program does"};
Option<bool> m_help{this, "help", false,
"displays information about the command line"};
Alias<bool> alias_help{this, '?', &m_help};
Option<bool> m_demo{this, "demo", false,
"runs my program in demonstration mode"};
Option<bool> m_maximize{this, "maximize", false,
"opens the main window maximized"};
Option<int> m_loops{this, "loops", 1,
"specifies the number of times to repeat"};
EnumOption<int> m_size{this, "size", 3,
{ {"s", 1},
{"small", 1},
{"m", 3},
{"med", 3},
{"medium", 3},
{"l", 5},
{"large", 5} } };
BeginOptionalArguments here{this};
Argument<std::string> m_file{this, "file-name", "",
"name of an existing file to open"};
} cl;
Шаблоны классов Argument
, Option
и Alias
объявлены в области действия базового класса CommandLine
, и вы можете специализировать их для своих собственных типов.,Каждый из них принимает указатель this
, имя опции, значение по умолчанию и описание для использования при печати синопсиса / использования команды.
Я все еще пытаюсь устранить необходимость разбрызгивания всех this
указатели там, но я не нашел способ сделать это без введения макросов.Эти указатели позволяют каждому члену регистрироваться в таблицах базового класса, которые управляют синтаксическим анализом.
Как только у вас есть экземпляр, существует несколько перегрузок метода для анализа ввода из строки или * 1016.* стиль аргумента вектора.Синтаксический анализатор обрабатывает синтаксис опций как в стиле Windows, так и в стиле Unix.
if (!cl.Parse(argc, argv)) {
std::string message;
for (const auto &error : cl.GetErrors()) {
message += error + "\n";
}
std::cerr << message;
exit(EXIT_FAILURE);
}
После анализа вы можете получить доступ к значению любой из опций, используя operator()
:
if (cl.m_help()) { std::cout << cl.GetUsage(); }
for (int i = 0; i < cl.m_loops(); ++i) { ... }
Вся библиотека занимает всего около 300 строк (без тестов).Экземпляры немного вздуты, так как таблицы синтаксического анализа являются частью экземпляра (а не класса).Но вам, как правило, нужен только один экземпляр для каждой программы, и удобство этого чисто декларативного подхода довольно мощное, и экземпляр можно сбросить, просто проанализировав новый ввод.