2011-08-19 16 views
26

Questa domanda riguarda la libreria program_options Boost di C++.Cosa è boost :: program_options :: notify() per?

Tutti i tutorial sono molto chiari che dovrei chiamare notify() sulla mia mappa variabile completata, ma non sono sicuro di cosa stia facendo per me. Commentando fuori non sembra avere alcun effetto, e la documentazione non andare troppo nei dettagli:

http://www.boost.org/doc/libs/1_47_0/doc/html/boost/program_options/notify.html

Altre fonti suggeriscono che corre funzioni "definite dall'utente". In tal caso, in che modo vengono registrate tali funzioni e cosa fanno? Potrebbero lanciare delle eccezioni?

risposta

20

notify() è un member function of value_semantic. È un hook fornito in modo che, una volta determinato il valore finale di un'opzione, qualsiasi azione da intraprendere con quell'opzione possa essere eseguita automaticamente e incapsulata nella propria funzione. Questo impedisce al codice di avere una funzione lunga che agisce su ciascuna delle opzioni. Man mano che le possibili opzioni crescono, questo tipo di codice procedurale può diventare ingombrante.

Potete vedere an example of setting a notify function in the Boost manual:

options_description desc; 
desc.add_options() 
    ("compression", value<int>()->default_value(10), "compression level") 
    ("email", value< vector<string> >() 
     ->composing()->notifier(&your_function), "email") 
    ; 

Queste dichiarazioni specificano che il valore predefinito della prima opzione è 10, che la seconda opzione può comparire più volte e tutte le istanze dovrebbe essere fusa, e che dopo aver eseguito l'analisi, la libreria chiamerà la funzione di chiamata tua_funzione, passando il valore dell'opzione "email" come argomento.

+0

Oh, lo vedo ora. Devi cercare "notifier", not notify. La funzione di notifica supera un riferimento const al valore, quindi non può modificarlo? Non vedo molto che tu possa fare con esso se non lanciare un'eccezione se l'opzione è "cattiva". – olooney

+0

@olooney: L'intento è quello di prendere qualsiasi azione prevista con tale opzione. Ad esempio, se si dispone di un'opzione che modifica il percorso di ricerca, la funzione di notifica modificherà il percorso di ricerca. Come noto nella mia risposta, è possibile eseguire la stessa logica nell'opzione di analisi del codice controllando singolarmente ciascuna opzione e quindi adottando un'azione, ma ciò può comportare un lungo blob procedurale difficile da leggere o modificare. –

+2

Certo, ma senza la possibilità di mutare la variabile_map, passare un handle opaco a un oggetto environment, o collegarlo a functor (usando boost :: function, say), si è veramente limitati alle eccezioni e agli effetti secondari * globali *. Ciò è comunque utile per cambiare la directory di lavoro o impostare un flag "verbose" globale, ma non è abbastanza generale per spostare la maggior parte dell'opzione di analisi nei notificatori. Forse dovrei provarlo prima di esprimere un giudizio, sto solo teorizzando qui. – olooney

4

Penso che tu sia sulla strada giusta quando si parla "funtore" ...

E 'abbastanza comune per la possibilità di essere trattati da passare il suo argomento (s) per il metodo di qualche oggetto. Questo può essere fatto più direttamente con i notificanti se è possibile avvolgere il metodo in qualcosa che notifier() accetterà come argomento. E tu puoi. (Se boost :: function ha un modo per farlo, non ne ho abbastanza familiarità (e sono troppo pigro per studiarlo ora) - il seguente usa le routine nell'intestazione funzionale da STDLIB.)

Esempio:

Una delle opzioni è --config-file, che accetta un argomento stringa, che indica il percorso di un file di configurazione non predefinito. Hai una classe chiamata ConfigParser. Senza notificanti, il codice potrebbe essere simile a questo:

ConfigParser *cp = new ConfigParser(); 
std::string cp_path; 
desc.add_options() 
    ("config-file", value<std::string>(&cp_path)->default_value("~/.myconfig"), "Config File") 
    // ... the rest of your options 
    ; 

cp->setPath(cp_path); 

Con notificanti:

#include <functional> 

ConfigParser *cp = new ConfigParser(); 
desc.add_options() 
    ("config-file", value<std::string>()->default_value("~/.myconfig")->notifier(std::bind1st(std::mem_fun(&ConfigParser::setPath), cp)), "Config File") 
    // ... the rest of your options 
    ; 
Problemi correlati