boost::program_options 位置选项
boost::program_options positional options
我有一个位置选项(一个文件名),我希望它是最后一个选项。用户可以在命令行中传入一堆东西,也可以使用 -F
作为文件名。但是,我希望用户也能够将文件名放在末尾。
例如:
./program --var 3 /path/to/file
我目前实现的代码允许调用者将文件名放在命令行的任意位置。有没有办法强制位置参数总是在 "regular" 之后?
这是我设置位置参数的方法:
pos_opts_desc.add("filename", -1);
并解析命令行:
store(
command_line_parser(argc, argv).options(opts_desc).positional(pos_opts_desc).run(),
opts_var_map);
在此先感谢您的帮助。
编辑添加:
我完全同意在命令行中的任何位置指定 -F
。但是,如果通过位置选项进行设置,我想确保位置选项在最后。
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
run()
member function gives you back an instance of type 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
class has a member options
which has an ordered list of all the options (unlike the variable map, which is ordered by option name - since it's a std::map
). So you can look up the "filename"
argument and check its 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
}
我有一个位置选项(一个文件名),我希望它是最后一个选项。用户可以在命令行中传入一堆东西,也可以使用 -F
作为文件名。但是,我希望用户也能够将文件名放在末尾。
例如:
./program --var 3 /path/to/file
我目前实现的代码允许调用者将文件名放在命令行的任意位置。有没有办法强制位置参数总是在 "regular" 之后?
这是我设置位置参数的方法:
pos_opts_desc.add("filename", -1);
并解析命令行:
store(
command_line_parser(argc, argv).options(opts_desc).positional(pos_opts_desc).run(),
opts_var_map);
在此先感谢您的帮助。
编辑添加:
我完全同意在命令行中的任何位置指定 -F
。但是,如果通过位置选项进行设置,我想确保位置选项在最后。
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
run()
member function gives you back an instance of type 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
class has a member options
which has an ordered list of all the options (unlike the variable map, which is ordered by option name - since it's a std::map
). So you can look up the "filename"
argument and check its 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
}