c++boostboost-program-options

How to store data in boost::program_options::variable_map?


I am currently trying to rework some code that was handed down to me. The original point of the code is to read a configuration file, and to set up the different options in the file in a boost::program_options::variable_map, which is then read throughout other parts of the code which is already working fine.

Here is the code I am trying to replace:

// Some helpful definitions
boost::program_options::variables_map vm;
std::string filecfg = "File_name";
std::ifstream ifs(filecfg.c_str());

// Setting options (This is command line example, but config file is the same)
boost::program_options::options_description df("Command Line");
df.add_options()
    ("help", "display help message")
    ("file-cfg,f", boost::program_options::value<std::string>(), "config file")
    ("version", "display version and revision number");

boost::program_options::parsed_options parsedc = boost::program_options::parse_config_file(ifs, df, true);
boost::program_options::store(parsedc, vm);
boost::program_options::notify(vm);
std::vector <std::string> unrc = boost::program_options::collect_unrecognized(parsedc.options, boost::program_options::include_positional)

My thinking it to simply replace the boost::program_options::parsed_options parsedc and create this object by myself. The problem I run into is simply that there is no documentation on how to do this. I think it is mostly because it is not designed to be used this way.

In any case, I am just looking to fill up the vm object with the options described in dc, and with values that I can hold in a separate data structure (like a vector).

Is it possible to simply add values to vm? Or do I have to go through a function such as boost::program_options::store()?

Any help would be greatly appreciated! Let me know if something is unclear, or if there is something you'd like me to try!

Thanks!


Solution

  • Yeah you can.

    Be aware that you will have to decide how to "mock"/"fake" the other semantics of it though. (E.g. you might want to masquerade the options as having been defaulted)

    Conceptually, variable_map would be a map<string, variable_value>. variable_value:

    Class holding value of option. Contains details about how the value is set and allows to conveniently obtain the value.

    Note also that because variable_value uses boost::any for storage you will have to be exact about the types you will store. (So, don't store "oops" if you need a std::string("ah okay")).

    Here's a simple demo:

    Live On Coliru

    #include <boost/program_options.hpp>
    #include <iostream>
    #include <iomanip>
    
    namespace po = boost::program_options;
    using namespace std::string_literals;
    
    int main(/*int argc, char** argv*/) {
        // Some helpful definitions
        po::variables_map vm;
    
        vm.emplace("file-cfg", po::variable_value("string"s, true));
        vm.emplace("log-level", po::variable_value(3, false));
        vm.emplace("option3", po::variable_value{});
        notify(vm);
    
        std::vector unrc = { "unrecognized"s, "options"s };
    
        for (auto& [name, value] : vm) {
            std::cout
                << "Name: " << name
                << std::boolalpha
                << "\tdefaulted:" << value.defaulted()
                << "\tempty:" << value.empty();
    
            if (typeid(std::string) == value.value().type())
                std::cout << " - string " << std::quoted(value.as<std::string>()) << "\n";
            else if (typeid(int) == value.value().type())
                std::cout << " - int " << value.as<int>() << "\n";
            else if (!value.empty())
                std::cout << " - unknown type\n";
        }
    }
    

    Prints

    Name: file-cfg  defaulted:true  empty:false - string "string"
    Name: log-level defaulted:false empty:false - int 3
    Name: option3   defaulted:false empty:true