2011-08-19 6 views
26

Esta pregunta es sobre la biblioteca C++ Boost program_options.¿Qué es boost :: program_options :: notify() for?

Todos los tutoriales son muy claros al decir que debo llamar al notify() en mi mapa de variables completo, pero no estoy seguro de lo que esto realmente está haciendo por mí. Al comentar que fuera no parece tener ningún efecto, y la documentación no entrar en mucho detalle:

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

Otras fuentes sugieren que se ejecute funciones "definidas por el usuario". Si es así, ¿cómo se registran esas funciones y qué hacen? ¿Podrían arrojar excepciones?

Respuesta

20

notify() es un member function of value_semantic. Es un gancho que se proporciona de modo que, una vez que se determina el valor final de una opción, cualquier acción que se deba tomar con esa opción se puede realizar automáticamente y se puede encapsular en su propia función. Esto evita que el código tenga una función larga que actúa en cada una de las opciones. A medida que crecen las posibles opciones, ese tipo de código de procedimiento puede ser difícil de manejar.

Se puede ver 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") 
    ; 

Estas declaraciones se especifica que el valor por defecto de la primera opción es 10, que la segunda opción puede aparecer varias veces y todas las instancias deberían fusionarse, y que una vez hecho el análisis, la biblioteca llamará a la función & your_function, pasando el valor de la opción "email" como argumento.

+0

Oh, lo veo ahora. Debe buscar "notificador", no notificar. La función de notificación ha pasado una referencia constante al valor, por lo que no puede mutarla? No veo mucho que puedas hacer aparte de arrojar una excepción si la opción es "mala". – olooney

+0

@olooney: La intención es que tomes lo que sea la acción prevista con esa opción. Por ejemplo, si tiene una opción que cambia la ruta de búsqueda, su función de notificador modificaría la ruta de búsqueda. Como señalo en mi respuesta, puede hacer esta misma lógica en su código de análisis de opciones al seleccionar cada opción individualmente y luego tomar alguna medida, pero eso puede dar como resultado un blob de procedimiento largo que es difícil de leer o modificar. –

+2

Claro, pero sin la capacidad de mutar el mapa_variable, pasar un identificador opaco a un objeto de entorno o enlazar con el funtor (usando la función boost ::, por ejemplo), está realmente limitado a excepciones y efectos secundarios * global *. Eso sigue siendo útil para cambiar el directorio de trabajo o establecer un indicador global "detallado", pero no es lo suficientemente general como para mover la mayor parte del análisis de opciones en notificadores. Quizás debería intentarlo antes de hacer un juicio, solo estoy teorizando aquí. – olooney

4

creo que usted está en el camino correcto cuando se habla de "funtor" ...

Es bastante común que una opción para ser procesada por pasar su argumento (s) con el método de un objeto. Esto se puede hacer más directamente con los notificadores si puede envolver el método en algo que notifier() aceptará como argumento. Y tu puedes. (Si la función boost :: tiene una forma de hacerlo, no estoy lo suficientemente familiarizado con ella (y soy demasiado flojo para estudiarla ahora): la siguiente usa las rutinas en el encabezado funcional de STDLIB.)

Ejemplo:

Una de las opciones es --config-file, tomando un argumento de cadena, que indica la ruta de un archivo de configuración no predeterminado. Tienes una clase llamada ConfigParser. Sin notificadores, el código podría ser algo como esto:

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 los notificadores:

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