Insert into boost::program_options::variables_map by index operator
Asked Answered
D

3

7

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

Discriminator answered 9/5, 2019 at 9:24 Comment(0)
W
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.

Wirewove answered 30/5, 2019 at 14:40 Comment(0)
P
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));
Podesta answered 9/5, 2019 at 9:51 Comment(9)
Since C++11 you could use std::map's at() to access and edit a key directly.Levant
@Levant Yes, but it throws an exception if the element does not exists. Here the question is how to add an element to the map.Podesta
Oops, please forget my comment. Sorry I misread the question, because I had a similar problem yesterday.Levant
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 itselfDiscriminator
@Discriminator In this case, just use the default_value option, see expanded answer.Podesta
@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.Discriminator
@Discriminator Perhaps you can call po::store multiple times, see Multiple SourcesPodesta
+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)Laellaertes
@simon Using std::map's standard methods to add to the variables_map spoils some functionality; see my answer to similar question for a reason why that's a bad idea (the another includes another way to add to variables_map)Firstrate
W
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.

Wirewove answered 30/5, 2019 at 14:40 Comment(0)
C
1

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;
China answered 28/8, 2023 at 14:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.