6

I have a boost::program_options::variables_map args. Now I want to insert into this map manually like a key-value pair. Example:

boost::program_options::variables_map args

args["document"] = "A";

args["flag"] = true;

The problem is that I already have these 2 options

desc.add_options()
    ("document", po::value<std::string>())
    ("flag", po::value<bool>());

but they are given empty input from the command line sometimes. So if they are empty, then I have to update them inside the po::variables_map args itself

etotientz
  • 373
  • 5
  • 18

3 Answers3

4

The library is designed to store the arguments after parsing from command line, or from a file. You cannot directly use the operator[] to assign values like a std::map because it returns a const reference, see the annotation here:

const variable_value & operator[](const std::string &) const;

If you really really want to assign manually the key values, you could create a std::stringstream and parse it with the library, see the following example program

#include <string>
#include <sstream>
#include <iostream>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

int main()
{
  namespace po = boost::program_options;

  std::stringstream s;
  s << "document=A" << std::endl << "flag=true" << std::endl;

  po::options_description desc("");
  desc.add_options()
    ("document", po::value<std::string>())
    ("flag", po::value<bool>());

  po::variables_map vm;
  po::store(po::parse_config_file(s, desc, true), vm);
  po::notify(vm);

  std::cout << "document is: " << vm["document"].as<std::string>() << std::endl;
  std::cout << "flag is: " << (vm["flag"].as<bool>() ? "true" : "false") << std::endl;

  return 0;
}

If you instead just want to insert a value for some keys when they are absent, you can just use the default_value options as described in the documentation of boost::program_options.

For example:

  po::options_description desc("");
  desc.add_options()
    ("document", po::value<std::string>()->default_value("default_document")
    ("flag", po::value<bool>()->default_value(false));
francesco
  • 7,189
  • 7
  • 22
  • 49
  • Since C++11 you could use std::map's at() to access and edit a key directly. – Simon May 09 '19 at 10:18
  • @Simon Yes, but it throws an exception if the element does not exists. Here the question is how to *add* an element to the map. – francesco May 09 '19 at 10:28
  • Oops, please forget my comment. Sorry I misread the question, because I had a similar problem yesterday. – Simon May 09 '19 at 10:31
  • The problem is that I already have these 2 options desc.add_options() ("document", po::value()) ("flag", po::value()); but they are given empty input from the command line sometimes.So if they are empty, then I have to update them inside the po::variables_map args itself – etotientz May 09 '19 at 12:06
  • @etotientz In this case, just use the ```default_value``` option, see expanded answer. – francesco May 09 '19 at 12:19
  • @francesco, thanks for that but I cannot keep it as default since the inputs are fetched from another service after the this po::store is called. – etotientz May 09 '19 at 12:24
  • @etotientz Perhaps you can call ```po::store``` multiple times, see [Multiple Sources](https://www.boost.org/doc/libs/1_70_0/doc/html/program_options/tutorial.html#id-1.3.32.4.5) – francesco May 09 '19 at 12:34
  • +1 to the std::stringstream solution. It is the only way not using the library internals to set a value when you cannot use `default_value` (for example when a default value of an option depends on the value of another option, like a filename) – Alejandro de Haro Sep 17 '20 at 11:03
  • @simon Using std::map's standard methods to add to the variables_map **spoils** some functionality; see [my answer to similar question](https://stackoverflow.com/questions/63780447/how-to-store-data-in-boostprogram-optionsvariable-map/73628916#73628916) for a reason why that's a bad idea (the another includes another way to add to variables_map) – Jan K Sep 07 '22 at 08:33
1

Since it publicly inherits from std::map<std::string, variable_value> it should be relatively safe to cast it to std::map and use as such:

(*static_cast<std::map<std::string, variable_value>*>(my_variable_map))[name] = value;

There's no guarantee that this is enough to make variable_map use it, but currently it seems to be: cpp, h.

It's annoying that this is needed.

himself
  • 4,806
  • 2
  • 27
  • 43
0

Found another way to set values in variables_map: just to call "parent" method for operator[]

Like that:

namespace po = boost::program_options;

po::variables_map my_map;

std::string my_val = "smth";
boost::any my_val_any;
my_val_any = my_val;

my_map.std::map< std::string, po::variable_value >::operator[]( "key" ).value() = "value"; //or:
my_map.std::map< std::string, po::variable_value >::operator[]( "key" ).value() = my_val_any;
Catherine
  • 11
  • 2