2010-05-29 9 views
16

Tengo un programa que genera gráficos usando diferentes modelos de varios niveles. Cada modelo de varios niveles consiste en una generación de un gráfico de semillas más pequeño (por ejemplo, 50 nodos) que se puede crear a partir de varios modelos (por ejemplo, para cada borde posible, elija incluirlo con probabilidad p).Manejar opciones complejas con las opciones de programa de Boost

Después de la generación del gráfico de semillas, el gráfico se expande a uno más grande (digamos 1000 nodos), utilizando uno de los otros modelos.

En cada una de las dos etapas, cada modelo requiere un número diferente de parámetros.

Me gustaría ser tener program_options analizar los diferentes parámetros posibles, de acuerdo con los nombres de los modelos.

Por ejemplo, supongo que tengo dos modelos de gráficos de semilla: SA, que tiene 1 parámetro, y SB, que tiene dos. También para la parte de expansión, tengo dos modelos: A y B, nuevamente con 1 y 2 parámetros, respectivamente. Me gustaría poder hacer algo como:

./graph_generator --seed=SA 0.1 --expansion=A 0.2 
./graph_generator --seed=SB 0.1 3 --expansion=A 0.2 
./graph_generator --seed=SA 0.1 --expansion=B 10 20 
./graph_generator --seed=SB 0.1 3 --expansion=B 10 20 

y tener los parámetros analizados correctamente. ¿Es eso posible?

Respuesta

23

Mediante el uso de un custom validator y boost::program_options::value::multitoken, se puede lograr el resultado deseado:

#include <iostream> 
#include <boost/lexical_cast.hpp> 
#include <boost/optional.hpp> 
#include <boost/program_options.hpp> 

// Holds parameters for seed/expansion model 
struct Model 
{ 
    std::string type; 
    boost::optional<float> param1; 
    boost::optional<float> param2; 
}; 

// Called by program_options to parse a set of Model arguments 
void validate(boost::any& v, const std::vector<std::string>& values, 
       Model*, int) 
{ 
    Model model; 
    // Extract tokens from values string vector and populate Model struct. 
    if (values.size() == 0) 
    { 
     throw boost::program_options::validation_error(
      "Invalid model specification"); 
    } 
    model.type = values.at(0); // Should validate for A/B 
    if (values.size() >= 2) 
     model.param1 = boost::lexical_cast<float>(values.at(1)); 
    if (values.size() >= 3) 
     model.param2 = boost::lexical_cast<float>(values.at(2)); 

    v = model; 
} 

int main(int argc, char* argv[]) 
{ 
    Model seedModel, expansionModel; 

    namespace po = boost::program_options; 
    po::options_description options("Generic options"); 
    options.add_options() 
     ("seed", 
      po::value<Model>(&seedModel)->multitoken(), 
      "seed graph model") 
     ("expansion", 
      po::value<Model>(&expansionModel)->multitoken(), 
      "expansion model") 
     ; 

    po::variables_map vm; 
    po::store(po::parse_command_line(argc, argv, options), vm); 
    po::notify(vm); 

    std::cout << "Seed type: " << seedModel.type << "\n"; 
    if (seedModel.param1) 
     std::cout << "Seed param1: " << *(seedModel.param1) << "\n"; 
    if (seedModel.param2) 
     std::cout << "Seed param2: " << *(seedModel.param2) << "\n"; 

    std::cout << "Expansion type: " << expansionModel.type << "\n"; 
    if (expansionModel.param1) 
     std::cout << "Expansion param1: " << *(expansionModel.param1) << "\n"; 
    if (expansionModel.param2) 
     std::cout << "Expansion param2: " << *(expansionModel.param2) << "\n"; 

    return 0; 
} 

La función validate probablemente necesita más rigor, pero usted consigue la idea.

Esto compila y trabaja para mí.

Cuestiones relacionadas