2012-08-02 14 views
5

Estoy construyendo un generador de gráficos usando Boost Graph y Program Options. Existen, por ejemplo, dos tipos de componentes C y W, cada uno con 1 fuente, 1 receptor y algunos parámetros adicionales para especificar la topología entre ellos. Me gustaría poder unirlos en la secuencia proporcionada por el orden de los argumentos de la línea de comando.¿Cómo se extrae la secuencia de opciones analizadas usando las Opciones del programa Boost?

Por ejemplo:

./bin/make_graph -c4,5,1 -w3,3 -c3,1,2 

debe crear un gráfico similar a lo siguiente:

C -- W -- C 

Pero:

./bin/make_graph -c4,5,1 -c3,1,2 -w3,3 

debe crear un gráfico similar a lo siguiente:

C -- C -- W 

Al usar boost :: program_options, no pude determinar cómo extraer el orden exacto ya que "compone" las opciones de la misma string_key en un mapa con value_type == vector < string> (en mi caso).

Al iterar sobre el mapa, la orden se pierde. ¿Hay alguna manera de no duplicar el análisis, pero tener una función llamada (quizás una devolución de llamada) cada vez que se analiza una opción? No pude encontrar documentación en esta dirección. ¿Cualquier otra sugerencia?

de convencerlo de que no estoy inventando esto, esto es lo que tengo hasta ahora:

namespace bpo = boost::program_options; 
    std::vector<std::string> args_cat, args_grid, args_web; 
    bpo::options_description desc("Program options:"); 
    desc.add_options() 
      .operator()("help,h","Displays this help message.") 
      .operator()("caterpillar,c",bpo::value< std::vector<std::string> >(&args_cat)->default_value(std::vector<std::string>(1,"4,7,2"), "4,7,2"),"Caterpillar tree with 3 parameters") 
      .operator()("grid,g",bpo::value< std::vector<std::string> >(&args_grid)->default_value(std::vector<std::string>(1,"3,4"), "3,4"),"Rectangular grid with 2 parameters") 
      .operator()("web,w",bpo::value< std::vector<std::string> >(&args_web)->default_value(std::vector<std::string>(1,"3,4"), "3,4"),"Web with 2 parameters") 
      ; 
    bpo::variables_map ops; 
    bpo::store(bpo::parse_command_line(argc,argv,desc),ops); 
    bpo::notify(ops); 
    if((argc < 2) || (ops.count("help"))) { 
     std::cout << desc << std::endl; 
     return; 
    } 
    //TODO: remove the following scope block after testing 
    { 
     typedef bpo::variables_map::iterator OptionsIterator; 
     OptionsIterator it = ops.options.begin(), it_end = ops.options.end(); 
     while(it != it_end) { 
      std::cout << it->first << ": "; 
      BOOST_FOREACH(std::string value, it->second) { 
       std::cout << value << " "; 
      } 
      std::cout << std::endl; 
      ++it; 
     } 
     return; 
    } 

me di cuenta de que yo también podría incluir el tipo como un parámetro y resolver este problema trivial, por ejemplo:

./bin/make_graph --component c,4,5,1 --component w,3,3 --component c,3,1,2 

pero que se está moviendo en la dirección de escribir un analizador/validador mismo (tal vez incluso sin usar Boost opciones de programa):

./bin/make_graph --custom c,4,5,1,w,3,3,c,3,1,2 
./bin/make_graph c,4,5,1,w,3,3,c,3,1,2 

¿Cómo recomendarían que haga esto de una manera elegante?

¡Gracias de antemano!

PD: He buscado en SO para "[boost] + opciones del programa de secuencia" y "[boost-program-options] + order" (y sus variantes) antes de publicar esto, por lo que me disculpo por adelantado si esto resulta ser un duplicado.

Respuesta

2

¿Qué tal esto:

./bin/make_graph c,4,5,1 c,3,1,2 w,3,3 

Dónde "c,4,5,1", "c,3,1,2" y "w,3,3" son argumentos posicionales que se almacenan (en orden) en un std::vector<std::string> (al igual que en este --input-filetutorial). Luego use Boost.Tokenizer o boost::algorithm::split para extraer los subtokens de cada cadena de argumentos.

Si los gráficos pueden ser complejos, debe considerar la posibilidad de que el usuario especifique un archivo de entrada que contenga los parámetros del gráfico. Boost.Program_Options puede analizar un usuario config file que usa la misma sintaxis que las opciones de línea de comando.

+0

Gracias. Acepto los archivos de configuración. Mi motivación era evitar archivos de E/S en un gran número de ejecuciones. – scribbleink

4

Desde que publiqué la pregunta, hice algunas excavaciones y tengo un "truco" que funciona con los ejemplos existentes que tenía arriba.

bpo::parsed_options p_ops = bpo::parse_command_line(argc,argv,desc); 
typedef std::vector< bpo::basic_option<char> >::iterator OptionsIterator; 
OptionsIterator it = p_ops.options.begin(), it_end = p_ops.options.end(); 
while(it != it_end) { 
    std::cout << it->string_key << ": "; 
    BOOST_FOREACH(std::string value, it->value) { 
     std::cout << value << " "; 
    } 
    std::cout << std::endl; 
    ++it; 
} 

La razón por la que llamo un hack se debe a que todos los accesos argumentos como cadenas, y uno tendría que extraer los tipos de ella al igual que BPO :: variables_map hace con la función .as<T>() miembro. EDITAR: También accede directamente a un miembro de la estructura de opciones.

Cuestiones relacionadas