boost::program_options config file option with multiple tokens
Asked Answered
S

3

15

I can not seem to be able to read from config file multitoken options like I can from command line. What is the syntax for the config file?

This is how the option description is added:

//parser.cpp
- - -
po::options_description* generic;
generic=new po::options_description("Generic options");
generic->add_options()
("coordinate",po::value<std::vector<double> >()->multitoken(),"Coordinates (x,y)");

After which I parse command and config-files.

On command line '--coordinate 1 2' works. However, when I try in config file:

coordinate = 1,2

or

coordinate= 1 2

It fails giving a invalid_option_value exception. So what exactly is the syntax for config files in case of multitoken options?

Stanzel answered 4/5, 2011 at 13:50 Comment(1)
you don't need to use new here. If you do, you risk having memory leaks.Privatdocent
V
6

You can achieve the behavior you seek by writing a custom validator. This custom validator accepts :

./progname --coordinate 1 2
./progname --coordinate "1 2"
#In config file:
coordinate= 1 2

Here is the code:

struct coordinate {
  double x,y;
};

void validate(boost::any& v,
  const vector<string>& values,
  coordinate*, int) {
  coordinate c;
  vector<double> dvalues;
  for(vector<string>::const_iterator it = values.begin();
    it != values.end();
    ++it) {
    stringstream ss(*it);
    copy(istream_iterator<double>(ss), istream_iterator<double>(),
      back_inserter(dvalues));
    if(!ss.eof()) {
      throw po::validation_error("Invalid coordinate specification");
    }
  }
  if(dvalues.size() != 2) {
    throw po::validation_error("Invalid coordinate specification");
  }
  c.x = dvalues[0];
  c.y = dvalues[1];
  v = c;
}
...
    po::options_description config("Configuration");
    config.add_options()
        ("coordinate",po::value<coordinate>()->multitoken(),"Coordinates (x,y)")
        ;

References:

Vetiver answered 4/5, 2011 at 15:14 Comment(0)
C
11

In your configuration file, put each element of your vector on a different line.

coordinate=1
coordinate=2
Confucius answered 16/12, 2011 at 13:43 Comment(0)
V
6

You can achieve the behavior you seek by writing a custom validator. This custom validator accepts :

./progname --coordinate 1 2
./progname --coordinate "1 2"
#In config file:
coordinate= 1 2

Here is the code:

struct coordinate {
  double x,y;
};

void validate(boost::any& v,
  const vector<string>& values,
  coordinate*, int) {
  coordinate c;
  vector<double> dvalues;
  for(vector<string>::const_iterator it = values.begin();
    it != values.end();
    ++it) {
    stringstream ss(*it);
    copy(istream_iterator<double>(ss), istream_iterator<double>(),
      back_inserter(dvalues));
    if(!ss.eof()) {
      throw po::validation_error("Invalid coordinate specification");
    }
  }
  if(dvalues.size() != 2) {
    throw po::validation_error("Invalid coordinate specification");
  }
  c.x = dvalues[0];
  c.y = dvalues[1];
  v = c;
}
...
    po::options_description config("Configuration");
    config.add_options()
        ("coordinate",po::value<coordinate>()->multitoken(),"Coordinates (x,y)")
        ;

References:

Vetiver answered 4/5, 2011 at 15:14 Comment(0)
N
0

During finding myself confronted with a similar problem, I took the code above from Rob's answer (from May 4th, 2011), but had to change a few things due to changes in the boost architecture and C++11. I only cite the parts that I changed (or would have changed). The rest that is not within the validate function stays the same. For conformity reasons, I added the necessary std:: prefixes.

namespace po = boost::program_options;

void validate(boost::any& v,
  const std::vector<std::string>& values,
  coordinate*, int) {
  coordinate c;
  std::vector<double> dvalues;
  for(const auto& val : values)  {
    std::stringstream ss(val);
    std::copy(std::istream_iterator<double>(ss), std::istream_iterator<double>(),
      std::back_inserter(dvalues));
    if(!ss.eof()) {
      throw po::invalid_option_value("Invalid coordinate specification");
    }
  }
  if(dvalues.size() != 2) {
    throw po::invalid_option_value("Invalid coordinate specification");
  }
  c.x = dvalues[0];
  c.y = dvalues[1];
  v = c;
}

The shift from po::validation_error to po::invalid_option_value was hinted in https://mcmap.net/q/824828/-how-to-pass-a-string-to-quot-validation_error-quot-method-from-boost-1-46

Nofretete answered 1/9, 2016 at 13:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.