2012-08-02 12 views
5

Sto costruendo un generatore di diagrammi usando Boost Graph e Program Options. Esistono, ad esempio, due tipi di componenti C e W, ciascuno con 1 sorgente, 1 sink e alcuni parametri aggiuntivi per specificare la topologia in mezzo. Mi piacerebbe essere in grado di unirli insieme nella sequenza fornita dall'ordine degli argomenti della riga di comando.Come si estrae la sequenza di opzioni analizzate usando le opzioni del programma di potenziamento?

Ad esempio:

./bin/make_graph -c4,5,1 -w3,3 -c3,1,2 

dovrebbe creare un grafico simile al seguente:

C -- W -- C 

Ma:

./bin/make_graph -c4,5,1 -c3,1,2 -w3,3 

dovrebbe creare un grafico simile al seguente:

C -- C -- W 

Utilizzando boost :: program_options, non è stato possibile determinare come estrarre l'ordine esatto poiché "compone" le opzioni dello stesso string_key in una mappa con valore_type == vettore < stringa> (nel mio caso).

iterando sulla mappa, l'ordine è perso. C'è un modo per non duplicare l'analisi, ma avere una funzione chiamata (forse una richiamata) ogni volta che viene analizzata un'opzione? Non sono riuscito a trovare documentazione in questa direzione. Qualche altro suggerimento?

di convincervi che io non sto inventando, ecco cosa ho finora:

namespace bpo = boost::program_options; 
    std::vector<std::string> args_cat, args_grid, args_web; 
    bpo::options_description desc("Program options:"); 
    desc.add_options() 
      .operator()("help,h","Displays this help message.") 
      .operator()("caterpillar,c",bpo::value< std::vector<std::string> >(&args_cat)->default_value(std::vector<std::string>(1,"4,7,2"), "4,7,2"),"Caterpillar tree with 3 parameters") 
      .operator()("grid,g",bpo::value< std::vector<std::string> >(&args_grid)->default_value(std::vector<std::string>(1,"3,4"), "3,4"),"Rectangular grid with 2 parameters") 
      .operator()("web,w",bpo::value< std::vector<std::string> >(&args_web)->default_value(std::vector<std::string>(1,"3,4"), "3,4"),"Web with 2 parameters") 
      ; 
    bpo::variables_map ops; 
    bpo::store(bpo::parse_command_line(argc,argv,desc),ops); 
    bpo::notify(ops); 
    if((argc < 2) || (ops.count("help"))) { 
     std::cout << desc << std::endl; 
     return; 
    } 
    //TODO: remove the following scope block after testing 
    { 
     typedef bpo::variables_map::iterator OptionsIterator; 
     OptionsIterator it = ops.options.begin(), it_end = ops.options.end(); 
     while(it != it_end) { 
      std::cout << it->first << ": "; 
      BOOST_FOREACH(std::string value, it->second) { 
       std::cout << value << " "; 
      } 
      std::cout << std::endl; 
      ++it; 
     } 
     return; 
    } 

mi rendo conto che avrei potuto includere anche il tipo come parametro e risolvere questo problema banalmente, ad esempio:

./bin/make_graph --component c,4,5,1 --component w,3,3 --component c,3,1,2 

ma che si muove nella direzione di scrivere un parser/validatore stesso (magari anche senza utilizzare Boost Opzioni programma):

./bin/make_graph --custom c,4,5,1,w,3,3,c,3,1,2 
./bin/make_graph c,4,5,1,w,3,3,c,3,1,2 

Come raccomanderesti di farlo in modo elegante?

Grazie in anticipo!

PS: ho cercato su SO per "[boost] + sequenza opzioni programma" e "[boost-programma-opzioni] + ordine" (e le loro varianti) prima di postare questo, quindi mi scuso in anticipo se questo si rivela essere un duplicato.

risposta

2

ne dite di questo:

./bin/make_graph c,4,5,1 c,3,1,2 w,3,3 

Dove "c,4,5,1", "c,3,1,2" e "w,3,3" sono argomenti posizionali che vengono memorizzati (in ordine) in un std::vector<std::string> (proprio come in questo --input-filetutorial). Quindi utilizzare Boost.Tokenizer o boost::algorithm::split per estrarre i subtokens da ciascuna stringa di argomenti.

Se i grafici possono essere complessi, è consigliabile prendere in considerazione la possibilità per l'utente di specificare un file di input che contiene i parametri del grafico. Boost.Program_Options può analizzare un utente config file che utilizza la stessa sintassi delle opzioni della riga di comando.

+0

Grazie. Sono d'accordo per quanto riguarda i file di configurazione. La mia motivazione era di evitare l'I/O dei file su un numero elevato di esecuzioni. – scribbleink

4

Da quando ho postato la domanda, ho fatto un po 'di scavo e ho un "trucco" che funziona con gli esempi esistenti che avevo sopra.

bpo::parsed_options p_ops = bpo::parse_command_line(argc,argv,desc); 
typedef std::vector< bpo::basic_option<char> >::iterator OptionsIterator; 
OptionsIterator it = p_ops.options.begin(), it_end = p_ops.options.end(); 
while(it != it_end) { 
    std::cout << it->string_key << ": "; 
    BOOST_FOREACH(std::string value, it->value) { 
     std::cout << value << " "; 
    } 
    std::cout << std::endl; 
    ++it; 
} 

La ragione per cui io lo chiamo un hack è perché accede tutti gli argomenti come stringhe, e uno avrebbe dovuto estrarre i tipi da esso tanto come BPO :: variables_map fa con la funzione .as<T>() membro. EDIT: accede anche a un membro della struttura di opzioni direttamente.

Problemi correlati