2010-05-29 14 views
16

Mam program, który generuje wykresy za pomocą różnych modeli wielopoziomowych. Każdy model wielopoziomowy składa się z generowania mniejszego grafu początkowego (np. 50 węzłów), który można utworzyć z kilku modeli (na przykład - dla każdej możliwej krawędzi, należy uwzględnić ją z prawdopodobieństwem p).Obsługa opcji złożonych z opcjami programu Boost

Po wygenerowaniu wykresu źródłowego wykres jest powiększany do większego (powiedzmy 1000 węzłów) za pomocą jednego z innych zestawów modeli.

W każdym z dwóch etapów każdy model wymaga innej liczby parametrów.

Chciałbym mieć opcje program_parace parsować różne możliwe parametry, zgodnie z nazwami modeli.

Załóżmy na przykład, że mam dwa modele wykresów początkowych: SA, który ma 1 parametr i SB, który ma dwa. Również dla części ekspansyjnej mam dwa modele: A i B, ponownie z 1 i 2 parametrami, odpowiednio. Chciałbym móc coś takiego:

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

i mieć poprawnie analizowane parametry. Czy to w ogóle jest możliwe?

Odpowiedz

23

Stosując custom validator i boost::program_options::value::multitoken można osiągnąć pożądany rezultat:

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

Funkcja validate prawdopodobnie potrzebuje więcej dyscypliny, ale masz pomysł.

Ten komponuje i działa dla mnie.