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]