1

my goal is to create a program which can handle arguments like this:

myProgram -i my_int=20 -s my_string=foo -f my_float=3.1415

Progress
my current programm can be executed like this:

myProgram -i 10 12 2 -s foobar anotherstring -f 3.1425 1.5
Notice: no names for the values
Ignore the multiple values

I've did this with boost program_options:

po::options_description desc("Allowed options");
desc.add_options()
    ("help", "produce help message")
    ("float,f", po::value< std::vector<float> >()->multitoken(), "add a float to the map")
    ("int,i", po::value< std::vector<int> >()->multitoken(),"add a int to the map")
    ("string,s", po::value< std::vector<std::string> >()->multitoken(),"add a string to the map")
    ;

What i've tried

i have tried to give po::value this type:
std::pair<std::string, std::vector<float> >
but that gives me a complie error

So my question is:

is it possible to handle program arguments like -s my_string=str with the boost library or not?

YvesHendseth
  • 1,149
  • 1
  • 10
  • 27

1 Answers1

1

First off, this grammar strikes me as more involved and you could consider writing a grammar for it.

This lets you be more flexible adding logic/constraints and also parsing into the AST types you envisioned more directly. For an example of this see this answer:

I found a relatively straightforward way in case you can change the provisional datatype to std::vector<std::pair<std::string, T> > instead.

Since conversions happen using lexical_cast<> you can read any value type that is input-streamable. Let's make std::pair input streamable:

namespace std {
    template <typename V> static inline std::istream& operator>>(std::istream& is, std::pair<std::string, V>& into) {
        char ch;
        while (is >> ch && ch!='=') into.first += ch;
        return is >> into.second;
    }
}

Now, you can just make the descriptions:

desc.add_options()
    ("help", "produce help message")
    ("float,f",  po::value<Floats>()->multitoken(),  "add a float to the map")
    ("int,i",    po::value<Ints>()->multitoken(),    "add a int to the map")
    ("string,s", po::value<Strings>()->multitoken(), "add a string to the map")
    ;

Lets parse your sample command line

po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc, po::command_line_style::default_style), vm);
po::notify(vm);

And print the results of the parse:

po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc, po::command_line_style::default_style), vm);
po::notify(vm);

std::cout << "Floats:";    for (auto p : vm["float"].as<Floats>())   std::cout << " ['" << p.first << "' -> " << p.second << "]";
std::cout << "\nInts:";    for (auto p : vm["int"].as<Ints>())       std::cout << " ['" << p.first << "' -> " << p.second << "]";
std::cout << "\nStrings:"; for (auto p : vm["string"].as<Strings>()) std::cout << " ['" << p.first << "' -> " << p.second << "]";

Live On Coliru

#include <boost/program_options.hpp>
#include <boost/program_options/cmdline.hpp>
#include <boost/any.hpp>
#include <vector>
#include <iostream>

namespace po = boost::program_options;

using Floats  = std::vector<std::pair<std::string, float>>;
using Ints    = std::vector<std::pair<std::string, int>>;
using Strings = std::vector<std::pair<std::string, std::string>>;

namespace std {
    template <typename V> static inline std::istream& operator>>(std::istream& is, std::pair<std::string, V>& into) {
        char ch;
        while (is >> ch && ch!='=') into.first += ch;
        return is >> into.second;
    }
}

int main(int argc, char** argv) {

    po::options_description desc("Allowed options");

    desc.add_options()
        ("help", "produce help message")
        ("float,f",  po::value<Floats>()->multitoken(),  "add a float to the map")
        ("int,i",    po::value<Ints>()->multitoken(),    "add a int to the map")
        ("string,s", po::value<Strings>()->multitoken(), "add a string to the map")
        ;


    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc, po::command_line_style::default_style), vm);
    po::notify(vm);

    std::cout << "Floats:";    for (auto p : vm["float"].as<Floats>())   std::cout << " ['" << p.first << "' -> " << p.second << "]";
    std::cout << "\nInts:";    for (auto p : vm["int"].as<Ints>())       std::cout << " ['" << p.first << "' -> " << p.second << "]";
    std::cout << "\nStrings:"; for (auto p : vm["string"].as<Strings>()) std::cout << " ['" << p.first << "' -> " << p.second << "]";
}

Prints:

Floats: ['my_float' -> 3.1415]
Ints: ['my_int' -> 20]
Strings: ['my_string' -> foo]
Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633