2016-05-05 3 views
3

У меня есть позиционная опция (имя файла), и я хочу, чтобы она была последней опцией. В принципе, пользователь может передать кучу материала в командной строке, а также использовать -F для имени файла. Однако я хочу, чтобы пользователь также имел возможность просто поместить имя файла в конец.boost :: program_options positional options

Например

./program --var 3 /path/to/file 

код, который я в настоящее время внедрили позволяет вызывающему поместить имя файла, где в командной строке. Есть ли способ заставить позиционные аргументы всегда появляться после «обычных»?

Вот как позиционный аргумент я настройка:

pos_opts_desc.add("filename", -1); 

И для разбора командной строки:

store(
    command_line_parser(argc, argv).options(opts_desc).postional(pos_opts_desc).run(), 
    opts_var_map); 

Заранее спасибо за помощь.

Edited добавить:

Я совершенно нормально с -F, устанавливается в любом месте в командной строке. Однако, если настройка была выполнена с помощью позиционной опции, я хочу убедиться, что позиционная опция находится в самом конце.

ответ

2

run() функция член дает Вам экземпляр типа parsed_options. Простое использование является фактически никогда не смотрят на этот объект и передать его непосредственно в store(), как в вашем примере:

po::store(
    po::command_line_parser(argc, argv).options(opts_desc).postional(pos_opts_desc).run(), 
    opts_var_map); 

Но мы можем удержать его и изучить его содержимое:

auto parsed = po::command_line_parser(argc, argv) 
    .options(opts_desc) 
    .postional(pos_opts_desc) 
    .run(); 
po::store(parsed, opts_var_map); 

parsed_options class имеет член options, который имеет , приказал список всех вариантов (в отличие от карты переменных, которая упорядочена по имени опции - так как это std::map). Таким образом, вы можете найти аргумент "filename" и проверить его член position_key. Мы хотим, чтобы либо: position_key == -1 (что означает, что он снабжен -F) или position_key == 0 и быть последним элементом в списке опций (это позиционная аргумент был последний аргумент):

auto it = std::find_if(parsed.options.begin(), parsed.options.end(), 
    [](po::option const& o){ return o.string_key == "filename"; }); 
if (it == parsed.options.end()) { 
    // fail: missing filename); 
} 
if (it->position_key != -1 && it != std::prev(parsed.options.end())) { 
    // fail: filename was positional but wasn't last 
} 
+0

Хотя я пошел с более C++ 98 маршрутом, этот ответ указал мне в правильном направлении. Благодарю. –

3

variables_map как название предлагает std::map, что позволяет нам использовать на нем регулярные функции STL.

if (vm.count("filename")) { 
     if (vm.find("filename") != std::prev(vm.rbegin()).base()) { 
     std::cout << "filename must go at the end."; 
     } 
    } 

Тестовые:

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp -lboost_system -lboost_program_options \ 
&& echo -n "Case 1 " && ./a.out asdf --foo=12 && echo \ 
&& echo -n "Case 2 " && ./a.out --foo=12 asdf && echo \ 
&& echo -n "Case 3 " && ./a.out asdf && echo \ 
&& echo -n "Case 4 " && ./a.out --foo=12 && echo \ 
&& echo -n "Case 5 " && ./a.out && echo \ 
&& echo -n "Case 6 " && ./a.out --foo=12 asdf asdf 

Результат:

Case 1 filename must go at the end. 
Case 2 
Case 3 
Case 4 
Case 5 
Case 6 option '--filename' cannot be specified more than once 
+0

Просто интересно ... есть есть способ различать опцию, устанавливаемую с помощью позиционного метода или через «-F»? Причина в том, что я в порядке с -F, где бы то ни было, но если он позиционный, я хочу, чтобы позиционный материал пришел в конце. –

+0

Да, это 'std :: map', что означает, что он отсортирован по имени аргумента - не по положению. – Barry

Смежные вопросы