【问题标题】:boost::program_options positional optionsboost::program_options 位置选项
【发布时间】:2016-05-05 22:07:02
【问题描述】:

我有一个位置选项(文件名),我希望它是最后一个选项。用户可以在命令行中传入一堆东西,也可以使用-F 作为文件名。但是,我希望用户也能够将文件名放在末尾。

例如:

./program --var 3 /path/to/file

我目前实现的代码允许调用者将文件名放在命令行中的任何位置。有没有办法强制位置参数总是在“常规”参数之后?

这是我设置位置参数的方式:

pos_opts_desc.add("filename", -1);

并解析命令行:

store(
    command_line_parser(argc, argv).options(opts_desc).positional(pos_opts_desc).run(),
    opts_var_map);

提前感谢您的帮助。

编辑添加:

我完全可以在命令行的任何位置指定-F。但是,如果设置是通过位置选项完成的,我想确保位置选项位于最后。

【问题讨论】:

    标签: c++ boost boost-program-options


    【解决方案1】:

    run() 成员函数返回一个 parsed_options 类型的实例。简单的用法是永远不要真正查看此对象并将其直接传递给store(),如您的示例所示:

    po::store(
        po::command_line_parser(argc, argv).options(opts_desc).positional(pos_opts_desc).run(),
        opts_var_map);
    

    但我们可以抓住它并检查它的内容:

    auto parsed = po::command_line_parser(argc, argv)
        .options(opts_desc)
        .positional(pos_opts_desc)
        .run();
    po::store(parsed, opts_var_map);
    

    parsed_options 类有一个成员options,它有一个所有选项的有序 列表(与按选项名称排序的变量映射不同——因为它是一个std::map) .因此,您可以查找 "filename" 参数并检查其 position_key 成员。我们想要:position_key == -1(这意味着它提供了-F)或position_key == 0,它是选项列表中的最后一个元素(它是一个位置参数,是最后一个参数):

    auto it = std::find_if(parsed.options.begin(),
                           parsed.options.end(),
                           [](po::option const& o) {
                             return o.string_key == "filename";
                           });
    
    if (it == parsed.options.end()) {
        // fail: missing filename);
    }
    
    if (it->position_key != -1 && it != std::prev(parsed.options.end())) {
        // fail: filename was positional but wasn't last
    }
    

    【讨论】:

    • 虽然我选择了更多的 C++98 路线,但这个答案为我指明了正确的方向。谢谢。
    【解决方案2】:

    variables_map 顾名思义就是std::map,它允许我们在其上使用常规的 STL 函数。

        if ( vm.count("filename") ) {
          if ( vm.find("filename") != std::prev(vm.rbegin()).base() ) {
            std::cout << "filename must go at the end.";
          }
        }
    

    测试用例:

    g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp -lboost_system -lboost_program_options \
    && echo -n "Case 1 " && ./a.out asdf --foo=12 && echo \
    && echo -n "Case 2 " && ./a.out --foo=12 asdf && echo \
    && echo -n "Case 3 " && ./a.out asdf && echo \
    && echo -n "Case 4 " && ./a.out --foo=12 && echo \
    && echo -n "Case 5 " && ./a.out && echo \
    && echo -n "Case 6 " && ./a.out --foo=12 asdf asdf
    

    结果:

    Case 1 filename must go at the end.
    Case 2 
    Case 3 
    Case 4 
    Case 5 
    Case 6 option '--filename' cannot be specified more than once
    

    【讨论】:

    • 只是好奇......有没有办法区分通过位置方法或“-F”设置的选项?原因是我可以接受 -F 在任何地方,但如果它是位置的,我希望位置的东西在最后。
    • 是的,它是std::map,这意味着它是按参数名称排序的,而不是按位置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 2020-08-29
    • 2012-08-27
    • 2011-12-29
    • 2016-02-22
    相关资源
    最近更新 更多