诀窍是强制boost
将所有数字分类为位置值(不要与 混淆positional_options_description
。您这样做的方式是定义 astyle_parser
并将其提供给command_line_parser
as a extra_style_parser
:
#include <boost/program_options/option.hpp>
#include <boost/lexical_cast/try_lexical_convert.hpp>
#include <boost/program_options/value_semantic.hpp>
using po = boost::program_options;
std::vector<po::option> ignore_numbers(std::vector<std::string>& args)
{
std::vector<po::option> result;
int pos = 0;
while(!args.empty()) {
const auto& arg = args[0];
double num;
if(boost::conversion::try_lexical_convert(arg, num)) {
result.push_back(po::option());
po::option& opt = result.back();
opt.position_key = pos++;
opt.value.push_back(arg);
opt.original_tokens.push_back(arg);
args.erase(args.begin());
} else {
break;
}
}
return result;
}
一旦你有了它,你就是这样使用它的:
po::store(po::command_line_parser(argc, argv)
.extra_style_parser(&po::ignore_numbers)
.options(commands)
.run(), vm);
您现在可以同时使用负数和短命令行参数。
但是,仍然存在一个问题,没有办法限制每个参数采用的标记数量,如果使用位置参数,这可能会出现问题。例如,这样的事情是行不通的:
foo --coords 1 2 3 4 bar.baz
为了解决这个问题,我们需要添加一种方法来强制参数所需的令牌数量:
template<class T, class charT = char>
class bounded_typed_value : public po::typed_value<T, charT>
{
public:
bounded_typed_value(T* store_to)
: typed_value<T, charT>(store_to), m_min(-1), m_max(-1) {}
unsigned min_tokens() const {
if(m_min < 0) {
return po::typed_value<T, charT>::min_tokens();
} else {
return (unsigned)m_min;
}
}
unsigned max_tokens() const {
if(m_max < 0) {
return po::typed_value<T, charT>::max_tokens();
} else {
return (unsigned)m_max;
}
}
bounded_typed_value* min_tokens(unsigned min_tokens)
{
if(min_tokens > 1) {
po::typed_value<T, charT>::multitoken();
}
m_min = min_tokens;
return this;
}
bounded_typed_value* max_tokens(unsigned max_tokens)
{
if(max_tokens > 1) {
po::typed_value<T, charT>::multitoken();
}
m_max = max_tokens;
return this;
}
bounded_typed_value* fixed_tokens(unsigned num_tokens)
{
if(num_tokens > 1) {
po::typed_value<T, charT>::multitoken();
}
m_min = num_tokens;
m_max = num_tokens;
return this;
}
private:
int m_min;
int m_max;
};
template<class T, class charT = char>
bounded_typed_value<T, charT>*
bounded_value()
{
return new bounded_typed_value<T, charT>(0);
}
你现在可以像这样把它们放在一起:
po::positional_options_description p;
p.add("file-name", -1);
boost::program_options::options_description desc;
desc.add_options()
("coords,c", boost::program_options::bounded_value<std::vector<double>>()->fixed_tokens(4), "Bounding box");
po::store(po::command_line_parser(argc, argv)
.extra_style_parser(&po::ignore_numbers)
.positional(p)
.options(commands)
.run(), vm);