I'm building a graph generator using Boost Graph and Program Options. There are, for example, two types of components C and W, each with 1 source, 1 sink and some additional parameters to specify topology in between. I'd like to be able to stitch them together in the sequence provided by the order of the command line arguments.
For example:
./bin/make_graph -c4,5,1 -w3,3 -c3,1,2
Should create a graph resembling the following:
C -- W -- C
But:
./bin/make_graph -c4,5,1 -c3,1,2 -w3,3
Should create a graph resembling the following:
C -- C -- W
Using boost::program_options, I was unable to determine how to extract the exact order since it "composes" the options of the same string_key into a map with value_type == vector< string > (in my case).
By iterating over the map, the order is lost. Is there a way to not duplicate the parsing, but have a function called (perhaps a callback) every time an option is parsed? I couldn't find documentation in this direction. Any other suggestions?
To convince you that I'm not making this up, here's what I have so far:
namespace bpo = boost::program_options;
std::vector<std::string> args_cat, args_grid, args_web;
bpo::options_description desc("Program options:");
desc.add_options()
.operator ()("help,h","Displays this help message.")
.operator ()("caterpillar,c",bpo::value< std::vector<std::string> >(&args_cat)->default_value( std::vector<std::string>(1,"4,7,2"), "4,7,2" ),"Caterpillar tree with 3 parameters")
.operator ()("grid,g",bpo::value< std::vector<std::string> >(&args_grid)->default_value( std::vector<std::string>(1,"3,4"), "3,4" ),"Rectangular grid with 2 parameters")
.operator ()("web,w",bpo::value< std::vector<std::string> >(&args_web)->default_value( std::vector<std::string>(1,"3,4"), "3,4" ),"Web with 2 parameters")
;
bpo::variables_map ops;
bpo::store(bpo::parse_command_line(argc,argv,desc),ops);
bpo::notify(ops);
if((argc < 2) || (ops.count("help"))) {
std::cout << desc << std::endl;
return;
}
//TODO: remove the following scope block after testing
{
typedef bpo::variables_map::iterator OptionsIterator;
OptionsIterator it = ops.options.begin(), it_end = ops.options.end();
while(it != it_end) {
std::cout << it->first << ": ";
BOOST_FOREACH(std::string value, it->second) {
std::cout << value << " ";
}
std::cout << std::endl;
++it;
}
return;
}
I realize that I could also include the type as a parameter and solve this problem trivially, e.g.:
./bin/make_graph --component c,4,5,1 --component w,3,3 --component c,3,1,2
but that's moving in the direction of writing a parser/validator myself (maybe even without using Boost Program Options):
./bin/make_graph --custom c,4,5,1,w,3,3,c,3,1,2
./bin/make_graph c,4,5,1,w,3,3,c,3,1,2
How would you guys recommend I do this in an elegant way?
Thanks in advance!
PS: I've searched on SO for "[boost] +sequence program options" and "[boost-program-options] +order" (and their variants) before posting this, so I apologize in advance if this turns out to be a duplicate.
Since posting the question, I did some digging and have a "hack" that works with the existing examples I had above.
bpo::parsed_options p_ops = bpo::parse_command_line(argc,argv,desc);
typedef std::vector< bpo::basic_option<char> >::iterator OptionsIterator;
OptionsIterator it = p_ops.options.begin(), it_end = p_ops.options.end();
while(it != it_end) {
std::cout << it->string_key << ": ";
BOOST_FOREACH(std::string value, it->value) {
std::cout << value << " ";
}
std::cout << std::endl;
++it;
}
The reason I call it a hack is because it accesses all arguments as strings, and one would have to extract the types from it much like bpo::variables_map does with the .as<T>()
member function. EDIT: It also accesses a member of the options struct directly.
How about this:
./bin/make_graph c,4,5,1 c,3,1,2 w,3,3
Where "c,4,5,1"
, "c,3,1,2"
and "w,3,3"
are positional arguments which are stored (in order) in a std::vector<std::string>
(just like --input-file
in this tutorial) . Then use Boost.Tokenizer or boost::algorithm::split
to extract the subtokens from each argument string.
If the graphs can be complex, you should consider making it possible for the user to specify an input file that contains the graph parameters. Boost.Program_Options can parse a user config file that uses the same syntax as the command line options.
来源:https://stackoverflow.com/questions/11769550/how-does-one-extract-the-sequence-of-parsed-options-using-boost-program-options