2011-08-19 6 views
26

To pytanie dotyczy biblioteki C++ Boost program_opcje.Do czego służy funkcja :: program_options :: notify()?

Wszystkie samouczki są bardzo jasne, że powinienem zadzwonić pod notify() na mojej ukończonej mapie zmiennej, ale nie jestem pewien, co to właściwie robi dla mnie. Komentując go nie wydaje się mieć żadnego wpływu, a dokumentacja nie wchodzić wiele szczegółów:

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

Inne źródła sugerują, że działa on funkcje „user-defined”. Jeśli tak, jak są rejestrowane te funkcje i co one robią? Może rzucają wyjątki?

Odpowiedz

20

notify() to member function of value_semantic. Jest to hak, który jest dostarczany w taki sposób, że po ustaleniu ostatecznej wartości opcji, wszelkie działania, które powinny zostać podjęte z tą opcją, mogą być wykonane automatycznie i zostać zakapsułkowane w jego własnej funkcji. Zapobiega to kodowi posiadającym jedną długą funkcję, która działa na każdą z opcji. Wraz z rozwojem możliwych opcji ten kod proceduralny może stać się nieporęczny.

Widać 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") 
    ; 

Deklaracje te określenia tej wartości domyślnej pierwszej opcji jest 10, że druga opcja może pojawić się kilka razy i wszystkie instancje powinny zostać połączone, i że po zakończeniu analizowania biblioteka będzie wywoływać funkcję funkcja, podając jako argument wartość opcji "e-mail" .

+0

Och, teraz to widzę. Musisz szukać "powiadamiającego", a nie powiadamiać. Funkcja powiadamiania jest za odniesieniem do wartości stałej, więc nie może jej zmutować? Nie widzę wiele, co możesz zrobić z tym innym niż wyrzucić wyjątek, jeśli opcja jest "zła". – olooney

+0

@olooney: Chodzi o to, abyś wziął wszystko, co zamierzała akcja z tą opcją. Na przykład, jeśli masz opcję, która zmienia ścieżkę wyszukiwania, funkcja powiadamiającego zmodyfikuje ścieżkę wyszukiwania. Jak zauważam w mojej odpowiedzi, można wykonać tę samą logikę w kodzie analizowania opcji, sprawdzając każdą opcję indywidualnie, a następnie podejmując pewne działania, ale może to spowodować długi obszar proceduralny, który jest trudny do odczytania lub zmodyfikowania. –

+2

Oczywiście, ale bez możliwości mutacji zmiennej_mapa, przekazania nieprzezroczystego uchwytu do obiektu środowiskowego lub powiązania z funktorem (używając funkcji boost :: function, powiedz), jesteś naprawdę ograniczony do wyjątków i * globalnych * efektów ubocznych. Nadal jest to przydatne przy zmianie katalogu roboczego lub ustawianiu globalnej flagi "pełnej", ale nie jest to wystarczająco ogólne, aby przenieść większość opcji analizowania do powiadamiających. Może powinienem spróbować, zanim jednak osądzę, po prostu teoretyzuję tutaj. – olooney

4

myślę, że jesteś na dobrej drodze, kiedy wspomina „funktor” ...

To dość typowe dla opcją być przetwarzane przez przepuszczenie jej argumentu (ów) do metody jakiegoś obiektu. Można to zrobić bardziej bezpośrednio z powiadamiającymi, jeśli można zawrzeć metodę w coś, co notifier() zaakceptuje jako argument. I możesz. (Jeśli funkcja boost :: ma taki sposób, nie jestem dostatecznie zaznajomiony z tym (i jestem zbyt leniwy, aby przejść do badania na nim teraz) - poniższe używa procedur w nagłówku funkcjonalnym od STDLIB.)

Przykład:

Jedną z opcji jest --config-file, pobierający ciąg znaków, który przekazuje ścieżkę do innego niż domyślny pliku konfiguracyjnego. Masz klasę o nazwie ConfigParser. Bez zgłaszających, kod może wyglądać mniej więcej tak:

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); 

ze zgłaszającym:

#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 
    ;