I'm using boost::program_options to get parameters from a config file.
i understand that i can create a file by hand and program options will parse it. but i'm looking for a way for the program to generate the file automatically. meaning printing out the name of the option and it's value. for example:
>./main 
without option would generate init.cfg that looks like this
[wave packet]
width = 1
position = 2.0
[calculation parameters]
levels = 15
then i would go into that file change the values using text editor and use this file:
>./main init.cfg
a nice way to approach this would be to have variables_map to have operator<<. this way i can just write it to file. change the values. read the file. all in the same format and no need to write each line.
i couldn't find anything like that in documentation or examples. please let me know if this is possible
EDIT: Sam Miller showed how to parse the ini file in sections. However, I still have a problem getting the values from boost::program_options::variables_map vm. i tried the following
  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";
  }
instead of it->second.value(), got an error. i also tried it->second. i also got an error:
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
i get the value correctly if i use it->second.as<int>() but not all of my values are ints and once i reach double, the program crashes with this:
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
                There's not a way using program_options that I'm aware of. You could use the property tree library to write the ini file.
Here is a short example:
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$ 
                        As far as I understand the question, it is about how to write config file based on given option_description.
Here is the possible, solution, how to write one options_description to config file. It relates on the fact that every parameter has some default value.
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);
}
Here algorithmsDesc is boost::program_options::options_description, that is where you describe options like:
algorithmsDesc_.add_options()
    ("general.blur_Width", po::value<int>(&varWhereToStoreValue)->default_value(3), "Gaussian blur aperture width")
The problem is if you need sections in config file. options_description doesn't have method to get caption passed through it's constructor. The dirty way to get it is to cut it from output stream made by 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)
}
Combining them together is straightforward.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With