2011-03-29 95 views
16

指示命令行程序选项结束的传统方法是使用选项--。我怎样才能得到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作为参数(当我希望找到final_args[0] == "foo"final_args[1] == "bar") 。我在这里假设--是一个以空字符串作为参数名称的长参数。如果相反,它应该被解释为一个简短的参数,以-作为参数名称,我该如何指定它?据我所知,将参数规范从""更改为",-"不会影响结果。

如何获得boost :: program_options正确处理--

编辑:下面是一个尝试做什么蒂姆·西尔维斯特建议通过创建一个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") 

--运行此在参数列表中导致required_option异常。 (我得到类似的结果,如果不是制作po::option每个尾随阿根廷,我收拾他们全部纳入po::option::original_tokens在一个po::option。)

+0

什么将遵循'--'在命令行? – 2011-03-29 16:40:31

+0

在我的具体情况下,它将介于零和两个文件名之间,包括两个文件名。我有一个以连字符开头的文件并不是不可能的。 – uckelman 2011-03-29 17:28:06

回答

4

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

我认为要做到这一点的方法是调用program_options::command_line_parser::extra_style_parser(),传递函数,通过引用,采用串的向量,并返回option S(见style_parser的typedef在cmdline.hpp)的向量。

您的函数将需要检测到第一个标记为“ - ”,创建一个新的option对象,将输入中的所有其他标记放入option的值向量并清空输入向量。请参阅program_options::detail::cmdline::parse_long_option等,在libs/program_options/src/cmdline.cpp中提供一些内容。

您可能需要注册一个特定的选项值才能使用,以便您可以在解析结束时轻松找到这个特殊的option对象,并从中提取一组附加的非选项参数。

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

编辑:

我觉得不好指点一下你在这并没有解决问题的方向,所以我回去,并得到它的工作。问题在于您的位置参数条目未设置为接受多个令牌,并且您没有填写valueprogram_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运行它打印help = 1 - foo,bar,baz,

+0

我试过你说的,没有成功。查看我编辑的代码问题。 – uckelman 2011-03-30 19:44:49

+0

@uckelman我多看了一下Boost代码,并且错过了两件事:'opt.value.push_back(* i)'和'po :: value ...-> multitoken()'。我会更新我的答案。 – 2011-03-31 20:07:12

+0

谢谢!我发现它也可以创建只有一个'po :: option'和push_back()所有剩余的值,而不是每次通过循环的'po :: option'。这种方式的效率可能稍高一点。 – uckelman 2011-04-01 13:14:37

4

有一个简单的,不令人满意的解决方法:在argvcommand_line_parser之前,检查是否发生--。如果是这样,请将argc重设为--的位置以将其隐藏并将其从command_line_parser后的参数隐藏起来。然后,在完成解析后,手动处理--后的位置参数。布莱什!

6

我有点困惑,因为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; 
} 
+0

如果你已经有其他的位置选择 - 我至少不能让它工作。 – 2018-01-14 12:49:09