2012-01-11 9 views

risposta

1

Ho sfogliato la documentazione Boost.Program_options, e non è affatto ovvio per me se è possibile farlo. Ho l'impressione che la libreria si occupi principalmente di analizzando la riga di comando, non di convalida. Potresti riuscire a elaborare qualcosa con un custom validator, ma ciò implica generare eccezioni quando ricevi input sbagliati (che potrebbero essere un errore più grave di quello che vuoi). Penso che questa caratteristica sia più orientata a far sì che tu abbia effettivamente una stringa, non che sia "gatto" o "cane".

La soluzione più semplice che posso pensare è quello di lasciare la biblioteca analizzare la linea di comando come normale, quindi aggiungere il proprio codice in seguito per verificare --arg è stato fissato a cat o dog. È quindi possibile stampare un errore ed uscire, ripristinare alcuni valori predefiniti adatti o qualsiasi cosa tu voglia.

17

È possibile utilizzare la funzione custom validator. Definire un tipo distinto per l'opzione, quindi sovraccaricare la funzione validate su quel tipo.

struct catdog { 
    catdog(std::string const& val): 
    value(val) 
    { } 
    std::string value; 
}; 

void validate(boost::any& v, 
       std::vector<std::string> const& values, 
       catdog* /* target_type */, 
       int) 
{ 
    using namespace boost::program_options; 

    // Make sure no previous assignment to 'v' was made. 
    validators::check_first_occurrence(v); 

    // Extract the first string from 'values'. If there is more than 
    // one string, it's an error, and exception will be thrown. 
    std::string const& s = validators::get_single_string(values); 

    if (s == "cat" || s == "dog") { 
    v = boost::any(catdog(s)); 
    } else { 
    throw validation_error(validation_error::invalid_option_value); 
    } 
} 

Le eccezioni generate da quel codice non sono diversi dalle eccezioni generate per ogni altro valore di opzione non valida, così si dovrebbe già essere pronti a gestirli.

Utilizzare il tipo di opzione speciale invece di string quando si definiscono le opzioni:

desc.add_options() 
    ("help", "produce help message") 
    ("arg", po::value<catdog>(), "set animal type") 
; 

ho composto un live example demonstrating use of this code.

+0

Questo esempio sembra molto simile a quello previsto nella [documentazione ufficiale] (http://www.boost.org/doc/libs/1_55_0/doc/html/program_options/howto.html#idp163429032) . Tuttavia, è necessario implementare una funzione di operatore di estrazione troppo 'std :: istream & operator >> (std :: istream & a, catdog e cd)' ' {' ​​' tornare in >> in.value;' ' } ' ' – russoue

+1

Sì, @Russoue, il mio codice è adattato direttamente dalla documentazione, a cui mi sono collegato in precedenza. Non so perché pensi che il codice abbia bisogno di un'estrazione del flusso, però. Ho incluso un esempio di lavoro che falsifica il tuo reclamo. La documentazione usa 'lexical_cast' per convertire dalla stringa di input al tipo di dati desiderato e, se si desidera utilizzare la stessa tecnica, sarà necessario implementare' operator >> '. Il mio esempio usa la costruzione diretta, comunque. * Come * creare il tipo personalizzato da una stringa va oltre lo scopo di questa domanda. –

5

Un approccio molto semplice è quello di avere "animale" come una stringa normale e dopo notificarlo testare e lanciare se necessario.

if (vm.count("animal") && (!(animal == "cat" || animal == "dog"))) 
     throw po::validation_error(po::validation_error::invalid_option_value, "animal"); 
+0

Non è questo ciò che Michael ha suggerito? –

+0

@RobKennedy Tranne che Michael ha detto "Ecco cosa si può fare", mentre Jorgen ha detto "Ecco cosa si può fare, ed ecco come sembrerebbe" –

Problemi correlati