2010-05-29 2 views
16

J'ai un programme qui génère des graphiques en utilisant différents modèles multi-niveaux. Chaque modèle à plusieurs niveaux consiste en une génération d'un graphe de graine plus petit (disons 50 nœuds) qui peut être créé à partir de plusieurs modèles (par exemple, pour chaque arête possible, choisissez de l'inclure avec la probabilité p). Après la génération du graphe de graine, le graphe est développé en un graphe plus grand (disons 1000 noeuds), en utilisant l'un d'un autre ensemble de modèles.Gérez les options complexes avec les options_programme de Boost

Dans chacune des deux étapes, chaque modèle nécessite un nombre différent de paramètres.

Je voudrais avoir program_options analyser les différents paramètres possibles, en fonction des noms des modèles. Par exemple, disons que j'ai deux modèles de graphe: SA, qui a 1 paramètre, et SB, qui en a deux. Aussi pour la partie expansion, j'ai deux modèles: A et B, à nouveau avec 1 et 2 paramètres, respectivement. Je voudrais pouvoir faire quelque chose comme:

./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 

et avoir les paramètres correctement analysés. Est-ce que c'est possible?

Répondre

23

En utilisant un custom validator et boost::program_options::value::multitoken, vous pouvez obtenir le résultat souhaité:

#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 fonction validate probablement besoin de plus de rigueur, mais vous voyez l'idée.

Cela compile et fonctionne pour moi.

Questions connexes