2011-01-16 14 views
12

Używam boost :: program_options do pobierania parametrów z pliku konfiguracyjnego.czy istnieje sposób drukowania pliku konfiguracyjnego dla opcji programu doładowania?

Rozumiem, że mogę utworzyć plik ręcznie i opcje programu będą analizowane. ale szukam sposobu, aby program automatycznie wygenerował plik. oznacza wydrukowanie nazwy opcji i jej wartości. na przykład:

>./main 

bez opcji będzie generować init.cfg który wygląda tak

[wave packet] 
width = 1 
position = 2.0 
[calculation parameters] 
levels = 15 

Potem pójdzie do tego pliku zmienić wartości za pomocą edytora tekstu, a do tego pliku:

>./main init.cfg 

dobrym sposobem podejścia byłoby mieć variable_map, aby mieć operator<<. w ten sposób mogę po prostu zapisać go do pliku. zmień wartości. przeczytaj plik. wszystkie w tym samym formacie i nie trzeba pisać każdej linii.

Nie mogłem znaleźć czegoś takiego w dokumentacji lub przykładach. proszę dać mi znać, jeśli to możliwe

EDYCJA: Sam Miller pokazał, jak przeanalizować plik ini w sekcjach. Jednak nadal mam problem z pobieraniem wartości z boost :: program_options :: variables_map vm. próbowałem następujące

for(po::variables_map::iterator it = vm.begin(); it != vm.end(); ++it) 
    { 
    if(it->first!="help"&&it->first!="config") 
    cout << "first - " << it->first << ", second - " << it->second.value() << "\n"; 
    } 

zamiast it->second.value(), masz błąd. Próbowałem także it->second. mam również błąd:

icpc -lboost_serialization -lboost_program_options -c programOptions.cc 
programOptions.cc(60): error: no operator "<<" matches these operands 
      operand types are: std::basic_ostream<char, std::char_traits<char>> << boost::any 
     cout << "first - " << it->first << ", second - " << it->second.value() << "\n"; 
                ^

compilation aborted for programOptions.cc (code 2) 
make: *** [programOptions.o] Error 2 

uzyskać wartość poprawnie w przypadku korzystania it->second.as<int>() ale nie wszystkie moje wartości są ints i raz sięgam dwukrotnie, program zawiesza się z tym:

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::bad_any_cast> >' 
    what(): boost::bad_any_cast: failed conversion using boost::any_cast 

Odpowiedz

12

Jest nie sposób za pomocą opcji programu, o których jestem świadomy. Można użyć biblioteki drzewa właściwości do write the ini file.

Oto krótki przykład:

macmini:stackoverflow samm$ cat property.cc 
#include <boost/property_tree/ptree.hpp> 
#include <boost/property_tree/ini_parser.hpp> 

#include <iostream> 

int 
main() 
{ 
    using boost::property_tree::ptree; 

    ptree root; 

    ptree wave_packet; 
    wave_packet.put("width", "1"); 
    wave_packet.put("position", "2.0"); 

    ptree calculation_parameters; 
    calculation_parameters.put("levels", "15"); 

    root.push_front(
      ptree::value_type("calculation parameters", calculation_parameters) 
      ); 
    root.push_front(
      ptree::value_type("wave packet", wave_packet) 
      ); 

    write_ini(std::cout, root); 

    return 0; 
} 

macmini:stackoverflow samm$ g++ property.cc 
macmini:stackoverflow samm$ ./a.out 
[wave packet] 
width=1 
position=2.0 
[calculation parameters] 
levels=15 
macmini:stackoverflow samm$ 
+0

Czy jest jakiś sposób na napisanie krótkiego przykładu? lub dać mapę drogową, jak to zrobić? –

+0

@kirill_igum Dodałem przykład. –

0

O ile dobrze rozumiem pytanie, chodzi o jak napisać plik konfiguracyjny na podstawie danego option_description.

Oto możliwe, rozwiązanie, jak napisać jeden opis options_ do pliku konfiguracyjnego. Dotyczy to faktu, że każdy parametr ma pewną wartość domyślną.

void SaveDefaultConfig() 
{ 
    boost::filesystem::ofstream configFile(configFilePath_); 
    auto descOptions = algorithmsDesc_.options(); 
    boost::property_tree::ptree tree; 

    for (auto& option : descOptions) 
    { 
     std::string name = option->long_name(); 
     boost::any defaultValue; 
     option->semantic()->apply_default(defaultValue); 

     if (defaultValue.type() == typeid(std::string)) 
     { 
      std::string val = boost::any_cast<std::string>(defaultValue); 
      tree.put(name, val); 
     } 
     ///Add here additional else.. type() == typeid() if neccesary 
    } 

    //or write_ini 
    boost::property_tree::write_json(configFile, tree); 
} 

Tutaj algorithmsDesc jest boost :: program_options :: options_description, czyli gdzie można opisać opcje takie jak:

algorithmsDesc_.add_options() 
    ("general.blur_Width", po::value<int>(&varWhereToStoreValue)->default_value(3), "Gaussian blur aperture width") 

Problem jest, jeśli trzeba sekcje w pliku konfiguracyjnym. options_description nie ma metody, aby napis został przekazany przez jego konstruktor. Brudna sposób na to jest, aby wyciąć go od strumienia wyjściowego wykonane przez print():

std::string getSectionName() 
{ 
    std::stringstream ss; 
    algorithmDesc_.print(ss) 

    std::string caption; 
    std::getline(ss,caption) 

    //cut last ':' 
    return caption.substr(0, caption.size() - 1) 
} 

łącząc je razem jest proste.

Powiązane problemy