使用' - '作为选项结束标记与boost :: program_options

时间:2011-03-29 16:17:47

标签: c++ boost-program-options

指示命令行程序选项结束的传统方式是使用选项--。如何让boost :: program_options将此识别为一个选项并接受命令行的其余部分作为位置参数?以下不起作用:

namespace po = boost::program_options;

po::positional_options_description posOpts;
posOpts.add("keywords", 1);
posOpts.add("input", 1);

std::vector<std::string> final_args;

po::options_description desc("Allowed Options");
desc.add_options()
  ...
  ("", po::value< std::vector<std::string> >(&final_args)->multitoken(), "end of options")
  ...
  ;

po::command_line_parser(argc, argv).options(desc).positional(posOpts).run();

如果我给foo bar作为参数,我在final_args中没有得到任何结果(正如预期的那样),但是当我给-- foo bar作为参数时(我希望找到{{1}时) }和final_args[0] == "foo")。我在这里假设final_args[1] == "bar"是一个长参数,空字符串作为其参数名称。相反,如果它应该被解释为一个短参数,以--作为参数名称,我该如何指定?就我所见,将参数规范从-更改为""不会影响结果。

如何让boost :: program_options正确处理",-"

修改:这是尝试通过创建--来完成Tim Sylvester所建议的内容:

extra_style_parser

std::vector<po::option> end_of_opts_parser(std::vector<std::string>& args) { std::vector<po::option> result; std::vector<std::string>::const_iterator i(args.begin()); if (i != args.end() && *i == "--") { for (++i; i != args.end(); ++i) { po::option opt; opt.string_key = "pargs"; opt.original_tokens.push_back(*i); result.push_back(opt); } args.clear(); } return result; } 已添加到以下选项中:

"pargs"

在参数列表中使用("pargs", po::value< std::vector<std::string> >(&pargs), "positional arguments") 运行此操作会导致--异常。 (如果不是为每个尾随arg制作required_option,我会得到类似的结果,我将它们全部打包到po::option po::option::original_tokens中。{/ p>

3 个答案:

答案 0 :(得分:7)

我有点困惑,因为boost::program_options已经完成了这一切:

$ ./testprog --the-only-option=23 aa --unknown bb
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::program_options::unknown_option> >'
  what():  unknown option unknown
Aborted

$ ./testprog --the-only-option=23 -- aa --unknown bb
the only option: 23
positional: aa
positional: --unknown
positional: bb

该计划:

#include <boost/program_options.hpp>

#include <iostream>
#include <vector>

using namespace std;

namespace po = boost::program_options;

static bool handle_command_line(int argc, char *argv[])
{
    po::options_description desc("Allowed options");
    desc.add_options()
        ("help", "Describe command line options")
        ("the-only-option", po::value<string>(), "some option")
        ;

    po::options_description hidden;
    hidden.add_options()
        ("positional", po::value<vector<string> >())
        ;

    po::options_description all_options;
    all_options.add(desc).add(hidden);

    po::positional_options_description p;
    p.add("positional", -1);

    po::variables_map vm;
    po::store(po::command_line_parser(argc, argv).
              options(all_options).positional(p).run(), vm);
    po::notify(vm);

    if (vm.count("help")) {
        cout << "Usage: " << argv[0] << " [options] [args]" << endl;
        cout << desc << "\n";
        return false;
    }

    if (vm.count("the-only-option"))
        cout << "the only option: " << vm["the-only-option"].as<string>() << endl;

    if (vm.count("positional")) {
        const vector<string> &v = vm["positional"].as<vector<string> >();
        vector<string>::const_iterator it = v.begin();
        for (; it != v.end(); ++it)
            cout << "positional: " << *it << endl;
    }

    return true;
}

int main(int argc, char *argv[])
{
    if (!handle_command_line(argc, argv))
        return 1;
    return 0;
}

答案 1 :(得分:6)

有一个简单但不满意的解决方法:在将argv移交给command_line_parser之前,请检查--是否出现在其中。如果是这样,请将argc重置为--的位置以隐藏它以及从command_line_parser开始跟踪它的参数。然后,在完成解析后,手动处理--之后的位置参数。布莱什!

答案 2 :(得分:4)

我有同样的问题,但放弃了。

我认为这样做的方法是调用program_options::command_line_parser::extra_style_parser(),向其传递一个函数,该函数通过引用获取字符串向量并返回option s的向量(请参阅style_parser cmdline.hpp)中的typedef。

您的函数需要检测第一个标记是&#34; - &#34;,创建一个新的option对象,将所有其余的标记放入{{1值向量并清空输入向量。请参阅option中的program_options::detail::cmdline::parse_long_option等,了解一些事情。

您可能需要注册要使用的特定选项值,以便在解析结束时轻松找到此特殊libs/program_options/src/cmdline.cpp对象,并从中提取一组其他非选项参数

我希望我能给你一些代码,但我从来没有真正做到这一点,我最终只是在stdin上每行添加一个额外的参数。

编辑:

我感到很难说你指的是没有解决问题的方向,所以我回去让它运转起来。问题是你的位置参数条目没有设置为接受多个标记而你没有填写optionvalue代码需要这两种代码,或者它不起作用。

这里有适合我的完整代码:

program_options

#include <boost/program_options.hpp> #include <iostream> namespace po = boost::program_options; typedef std::vector<std::string> stringvec; std::vector<po::option> end_of_opts_parser(stringvec& args) { std::vector<po::option> result; stringvec::const_iterator i(args.begin()); if (i != args.end() && *i == "--") { for (++i; i != args.end(); ++i) { po::option opt; opt.string_key = "pargs"; opt.value.push_back(*i); // <== here opt.original_tokens.push_back(*i); result.push_back(opt); } args.clear(); } return result; } int main(int argc, char* argv[]) { po::options_description desc("Allowed Options"); desc.add_options() ("help,h", "produce help message") ("pargs", po::value<stringvec>()->multitoken(), "positional arguments"); // and here ^^^^^^^^^^^^^ po::command_line_parser clparser(argc, argv); clparser.extra_style_parser(end_of_opts_parser); po::variables_map vm; po::store(clparser.options(desc).run(), vm); po::notify(vm); bool const help = !vm["help"].empty(); std::cout << "help = " << help << " - "; // in addition, you don't need to use a separate vector of strings: stringvec const& pargs = vm["pargs"].as<stringvec>(); std::copy(pargs.begin(), pargs.end(), std::ostream_iterator<std::string>(std::cout, ",")); return 0; } 一起使用时,会打印-h -- foo bar baz