2012-10-06 7 views
8

sto usando program_options spinta 1.50.0Desiderare consentire che le opzioni vengano specificate più volte quando si utilizzano le opzioni del programma boost. In questo momento ho più occorrenze

Voglio permettere il seguente per il mio programma foobar foobar --debug 2 --debug 3

Dal codice program_options spinta, c'è un esempio che regex.cpp mostra la creazione di un nuovo tipo e la creazione di un validatore per quel tipo.
ho provato, e funziona, ma ora non posso usare alcuni degli altri add_options() typed_value opzioni, come default_value, composizione, ecc

Ecco quello che ho provato finora:

#include <boost/program_options.hpp> 

    using namespace boost; 

    using namespace boost::program_options; 

    #include <iostream> 
    using namespace std; 
    struct lastmultioccurrenceint { 
     public: 
     lastmultioccurrenceint(int n) : n(n) {} 
     int n; 
    };  

void validate(boost::any& v, 
        const std::vector<std::string>& xs, 
        //const std::vector< std::basic_string<charT> >& xs, 
        lastmultioccurrenceint* , int) 
    { 
     using namespace boost::program_options; 

     cerr << "IN VALIDATE" << endl; 
     //validators::check_first_occurrence(v); 
     string s = validators::get_single_string(xs); 
     if (!v.empty()) { 
      cerr << "\tPRINTTING MULTIOCCURENCE WARNING, allowing v to be overwritten" << endl; 
      cerr << "\tEarlier value was: " << boost::any_cast<int>(v) << endl; 
      cerr << "\tNew value is: " << s << endl; 
     } 
     try { 
      //v = any(lastmultioccurrenceint(lexical_cast<int>(sx))); 
      //v = any(lexical_cast<int>(sx)); // works 
      v = any(lexical_cast<int>(s)); 
      //v = any(lexical_cast<lastmultioccurrenceint>(s)); 
      //v = any(4); 
     //} 
     /*catch(const bad_lexical_cast&) { 
      boost::throw_exception(validation_error::invalid_option_value(s)); 
     } */ 
     } 
     catch(const bad_lexical_cast&) { 
      throw validation_error(validation_error::invalid_option_value); 
     } 
     cerr << "made it through" << endl; 

     int main (int argc, char **argv) { 

    variables_map m_varMap; 
     // define style 
     // unix_style = (allow_short | short_allow_adjacent | short_allow_next 
     //   | allow_long | long_allow_adjacent | long_allow_next 
     //   | allow_sticky | allow_guessing 
     //   | allow_dash_for_short), 
     // ... allows typical unix-style options 
     // allow_long_disguise = can use "-" instead of "--" 
     // Reference: http://www.boost.org/doc/libs/1_42_0/doc/html/boost/program_options/command_line_style/style_t.html 
     // 
    try { 

    ProgOpts::command_line_style::style_t style = ProgOpts::command_line_style::style_t(
      ProgOpts::command_line_style::unix_style | 
      //ProgOpts::command_line_style::case_insensitive | 
      ProgOpts::command_line_style::allow_long_disguise); 

    options_description options("YDD"); 

    //lastmultioccurrenceint debugOpt; 

    options.add_options() 
    ("debug", value<lastmultioccurrenceint>(), "debug value (0-4), default is 0 (performance mode)") 
    //("debug", value<lastmultioccurrenceint>(&debugOpt)->default_value(0)->composing(), "debug value (0-4), default is 0 (performance mode)") 
    ; 

     //ProgOpts::parsed_options firstPreParsed = ProgOpts::command_line_parser(argc,argv).options(options).style(style).allow_unregistered().run(); 
     ProgOpts::parsed_options firstPreParsed = ProgOpts::command_line_parser(argc,argv).options(options).allow_unregistered().run(); 
    ProgOpts::store(firstPreParsed, m_varMap); 

    ProgOpts::notify(m_varMap); 
    } 
    /*catch (boost::program_options::multiple_occurrences &e) { 
     cerr << "GOT MULTIPLES" << endl; 
     cerr << "Option Name: " << e.get_option_name() << endl; 
     cerr << e.what() << endl; 
    } 
    catch(boost::bad_any_cast& e) { 
     cerr << "WRONG TYPE" << endl; 
     cerr << e.what() << endl; 
    } */ 
    catch(std::exception& e) { 
     cerr << "SOMETHING ELSE" << endl; 
     cerr << e.what() << endl; 
    } 
    catch(...) { 
     cerr << "UNKNOWN ERROR" << endl; 
    } 

    cerr << "DEBUG OPT IS: " << m_varMap["debug"].as<int>() << endl; 
} 

Quindi, se faccio: foobar --debug 2 --debug 3

Se commento fuori l'opzione di debug corrente ....

("debug", value<lastmultioccurrenceint>(), "debug value (0-4), default is 0 (performance mode)") 

... e rimuovere il commento le due righe seguenti:

lastmultioccurrenceint debugOpt; 
("debug", value<lastmultioccurrenceint>(&debugOpt)->default_value(0)->composing(), "debug value (0-4), default is 0 (performance mode)") 

... allora non anche compilare.

Sai come fare in modo che mi permetta di usare default_value e comporre? Potrebbe ereditare da typed_value, ma non ho ancora trovato un buon modo per farlo.

+0

Non è chiaro per me quello che stai cercando di raggiungere. La libreria supporta prontamente quella che sembra essere la sintassi desiderata 'foobar --debug 2 --debug 3' con un' std :: vector 'come tipo di opzione. –

+0

Voglio la seconda opzione per sovrascrivere la prima opzione. Quindi, nel tuo esempio, impostare l'opzione di debug su 3. –

risposta

5

Non penso che sia necessario definire un tipo personalizzato con un validatore per ottenere il risultato desiderato. Può essere fatto con il supporto semantico esistente delle informazioni della biblioteca. Considerate questo esempio

#include <boost/assign/list_of.hpp> 
#include <boost/program_options.hpp> 
#include <boost/version.hpp> 

#include <iostream> 

int 
main(int argc, char** argv) 
{ 
    namespace po = boost::program_options; 

    po::options_description desc("Options"); 

    typedef std::vector<unsigned> DebugValues; 
    DebugValues debug; 
    desc.add_options() 
     ("help,h", "produce help message") 
     ("debug", po::value<DebugValues>(&debug)->default_value(boost::assign::list_of(0), "0")->composing(), "set debug level") 

     ; 

    po::variables_map vm; 
    try { 
     const po::positional_options_description p; // note empty positional options 
     po::store(
       po::command_line_parser(argc, argv). 
          options(desc). 
          positional(p). 
          run(), 
          vm 
         ); 
     po::notify(vm); 

     if (vm.count("help")) { 
      std::cout << desc << "\n"; 
      std::cout << "boost version: " << BOOST_LIB_VERSION << std::endl; 
      return 0; 
     } 
    } catch (const boost::program_options::error& e) { 
     std::cerr << e.what() << std::endl; 
    } 

    std::cout << "got " << debug.size() << " debug values" << std::endl; 
    if (!debug.empty()) { 
     DebugValues::const_iterator value(debug.end()); 
     std::advance(value, -1); 
     std::cout << "using last value of " << *value << std::endl; 
    } 
} 

e il campione utilizzo:

samm$ ./a.out -h 
Options: 
    -h [ --help ]   produce help message 
    --debug arg (=0)  set debug level 

boost version: 1_46_1 
samm$ ./a.out --debug 1 --debug 2 
got 2 debug values 
using last value of 2 
samm$ ./a.out --debug 4 --debug 1 
got 2 debug values 
using last value of 1 
samm$ ./a.out --debug 4 --debug 1 --debug 9 
got 3 debug values 
using last value of 9 
samm$ 
+0

Vedo il tuo punto, ma voglio poter accedere all'opzione di debug come numero intero per tutto il programma. –

+0

Ad esempio: 'modello T CCommandLineArgs :: GetOption (const string & strOption) const' è una funzione che utilizzo per accedere a tutti gli argomenti della riga di comando. Ho diversi punti nel mio programma in cui chiamo 'GetOption (" debug ")'. Vorrei mantenere questo tipo di interfaccia per tutte le opzioni della riga di comando. –

+0

Dentro "GetOption" Non voglio avere un codice speciale per opzioni particolari. Immagino che potrei solo guardare il tipo DebugValues ​​e fare quello che suggerisci ogni volta che è il tipo di dati usati .... –

Problemi correlati