2016-05-05 4 views
3

Ich habe eine positionale Option (ein Dateiname) und ich möchte, dass es die letzte Option ist. Im Grunde kann der Benutzer eine Menge Dinge in der Befehlszeile übergeben und auch -F für den Dateinamen verwenden. Ich möchte jedoch, dass der Benutzer auch die Möglichkeit hat, den Dateinamen am Ende zu platzieren.boost :: program_options Positionsoptionen

Zum Beispiel

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

Der Code, den ich zur Zeit umgesetzt haben, kann der Anrufer den Namen der Datei, wo immer in der Befehlszeile platzieren. Gibt es trotzdem die Positionsargumente zu zwingen, immer nach den "normalen" zu kommen?

Hier ist, wie ich Set-up, die das Positions Argument:

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

Und die Befehlszeile zu analysieren:

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

Vielen Dank im Voraus für die Hilfe.

Edited hinzufügen:

ich vollkommen in Ordnung bin mit -F überall in der Befehlszeile angegeben werden. Wenn die Einstellung jedoch über die Positionsoption vorgenommen wurde, möchte ich sicherstellen, dass die Positionsoption ganz am Ende ist.

Antwort

2

Die run() Memberfunktion parsed_options Sie wieder eine Instanz vom Typ gibt. Die einfache Bedienung ist es, nie zu diesem Objekt tatsächlich aussieht und gibt es direkt in store(), wie in Ihrem Beispiel:

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

Aber wir können daran festhalten und seinen Inhalt untersuchen:

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

Die parsed_options Klasse hat ein Mitglied options, die eine geordnete Liste aller Optionen hat (anders als die Variable Karte, die nach Optionsname bestellt ist - da es ein std::map ist). So können Sie das "filename" Argument nachschlagen und sein position_key Mitglied überprüfen. Wir wollen entweder: position_key == -1 (was bedeutet, es mit -F versehen) oder position_key == 0 und es ist das letzte Element in der Liste der Optionen zu sein (es war ein Positions Argument, dass das letzte Argument war):

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

Obwohl ich mit einer mehr C++ 98 Route ging, wies diese Antwort mich in die richtige Richtung. Vielen Dank. –

3

variables_map ist, wie der Name schon sagt, eine std::map, die uns erlaubt, normale STL-Funktionen darauf zu verwenden.

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

Testfälle:

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 

Ergebnis:

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

Einfach nur neugierig ... ist Gibt es eine Möglichkeit, zwischen der Einstellung über die Positionsmethode oder über "-F" zu unterscheiden? Grund ist, dass ich OK bin, wenn -F überall ist, aber wenn es positionell ist, möchte ich, dass die Positionsdaten am Ende kommen. –

+0

Ja, es ist eine 'std :: map', was bedeutet, dass es nach Argumentnamen sortiert ist - nicht nach Position. – Barry