5

我正在使用 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< string > 的映射中(在我的例子中)。

通过遍历地图,顺序会丢失。有没有办法不重复解析,但每次解析选项时都有一个调用函数(可能是回调)?我找不到这个方向的文档。还有其他建议吗?

为了让你相信我不是在编造这个,这是我目前所拥有的:

    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 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

你们会如何建议我以优雅的方式做到这一点?

提前致谢!

PS:在发布之前,我已经在 SO 上搜索了“[boost] +sequence program options”和“[boost-program-options] +order”(及其变体),所以如果结果是这样,我提前道歉重复。

4

2 回答 2

4

自从发布问题以来,我进行了一些挖掘并有一个“hack”,它适用于我上面的现有示例。

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>()成员函数所做的那样。编辑:它还直接访问选项结构的成员。

于 2012-08-02T17:16:58.640 回答
2

这个怎么样:

./bin/make_graph c,4,5,1 c,3,1,2 w,3,3

其中"c,4,5,1"和是位置参数"c,3,1,2",它们(按顺序)存储在 a 中(就像在本教程中一样)。然后使用Boost.Tokenizer或从每个参数字符串中提取子标记。"w,3,3"std::vector<std::string>--input-fileboost::algorithm::split

如果图形可能很复杂,您应该考虑让用户指定一个包含图形参数的输入文件。Boost.Program_Options 可以解析使用与命令行选项相同语法的用户配置文件。

于 2012-08-02T03:27:03.167 回答