我正在使用Boost Graph和Program Options构建图形生成器。例如,有两种类型的组件C和W,每种组件具有1个源,1个接收器和一些附加参数以指定其间的拓扑。我希望能够按照命令行参数的顺序将它们拼接在一起。
例如:
./bin/make_graph -c4,5,1 -w3,3 -c3,1,2
应创建类似以下内容的图表:
C -- W -- C
可是:
./bin/make_graph -c4,5,1 -c3,1,2 -w3,3
应创建类似以下内容的图表:
C -- C -- W
使用boost :: program_options,我无法确定如何提取确切的顺序,因为它将相同string_key的选项“组合”到具有value_type == vector<的地图中。字符串> (就我而言)。
通过迭代地图,订单将丢失。有没有办法不重复解析,但每次解析一个选项时都有一个叫做(可能是回调)的函数?我找不到这方面的文件。还有其他建议吗?
为了说服你我没有说明这一点,这就是我到目前为止所做的:
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;
}
我意识到我还可以将类型作为参数包含在内并简单地解决这个问题,例如:
./bin/make_graph --component c,4,5,1 --component w,3,3 --component c,3,1,2
但是我正朝着自己编写解析器/验证器的方向发展(甚至可能不使用Boost程序选项):
./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
你们怎么建议我以优雅的方式做到这一点?
提前致谢!
PS:我在发布之前在SO上搜索了“[boost] +顺序程序选项”和“[boost-program-options] + order”(以及它们的变体),所以如果这一转,我会提前道歉是重复的。
答案 0 :(得分:4)
自从发布问题以来,我做了一些挖掘工作并且有一个“黑客”,它与我上面的现有例子一致。
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;
}
我称之为hack的原因是因为它将所有参数作为字符串访问,并且必须从中提取类型,就像bpo :: variables_map与.as<T>()
成员函数一样。编辑:它还直接访问选项结构的成员。
答案 1 :(得分:2)
这个怎么样:
./bin/make_graph c,4,5,1 c,3,1,2 w,3,3
其中"c,4,5,1"
,"c,3,1,2"
和"w,3,3"
是位置参数,它们(按顺序)存储在std::vector<std::string>
中(就像{{} 1}}在此tutorial)中。然后使用Boost.Tokenizer或boost::algorithm::split
从每个参数字符串中提取子字符。
如果图形可能很复杂,则应考虑使用户可以指定包含图形参数的输入文件。 Boost.Program_Options可以解析使用与命令行选项相同语法的用户config file。