2010-11-05 47 views
9

我需要能够让boost::program_options解析在命令行上传递的双打 的数组。对于积极的双打,这是没有问题的,当然是 (在add_options中使用std::vector<double>进行多重口令),但对于 否定的,我知道这些是不明确的参数。使用boost :: program_options接受负双打

这里是我想采取什么样的演示:

 
mycommand --extent -1.0 -2.0 -3.0 1.0 2.0 3.0 --some-other-argument somevalue 

程度要由Bounds类至少有一个构造 这需要六个个人T参数(在支持这种情况 - double)。

template <typename T> 
class Bounds 
{ 
public: 
    typedef T value_type; 
    typedef typename std::vector< Range<T> >::size_type size_type; 

    typedef typename std::vector< Range<T> > Ranges; 

    Bounds(T minx, T miny, T minz, 
      T maxx, T maxy, T maxz) 
    { 
     // fill Ranges vector 
    } 

private: 
    Ranges ranges; 
}; 

还有什么我必须提供支持使用add_options采取在Bounds类?我想 喜欢做类似的事情。可能?

namespace po = boost::program_options; 
po::options_description options("options"); 

options.add_options() 
    ("extent,e", po::value< Bounds<double> >(), "Extent to clip points to") 

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

po::notify(vm); 

if (vm.count("extent")) 
{ 
    Bounds<double> bounds = vm["extent"].as< Bounds<double> >(); 
    // do other stuff 
} 
+1

在与IRC的program_options作者交谈之后,确定目前这是不可能的。解决方法是禁用短期选项或使用引号。我选择了报价。 – 2011-01-27 16:35:43

+0

我已经将它作为票证报告过,也许它会在不久的将来得到解决:https://svn.boost.org/trac/boost/ticket/5201 – mloskot 2011-02-18 21:43:54

回答

1

处理负数的方法指定here也可能适用于您。

我被这个简单的解析器

store(command_line_parser(argc, argv).options(commands).run(), vm); 

解析它,但解决办法是使用扩展 一个:

parse_command_line 
+0

请注意,此解决方案基于禁用简短选项,因此解析器会忽略任何以连字符开头 – mloskot 2010-11-05 22:39:14

+0

@mloskot - 有趣的是,因为该线程上的OP特别要求处理-ve以及+ ve值。我希望这个讨论也适用于此,但没有尝试过。 – 2010-11-05 22:48:19

+0

我认为问题是将负数作为值处理,同时允许 - 选项和 - 选项。目前program_options分析负值作为选项名称(短风格) – mloskot 2010-11-06 13:24:13

1

最简单的方法是将您的参数封装在引号中: mycommand --e xtent'-1.0 -2.0 -3.0 1.0 2.0 3.0' - 某些其他参数somevalue

6

诀窍是强制boost将所有数字分类为位置值(不要与positional_options_description混淆。你这样做的方式是定义一个style_parser,并把它交给command_line_parser作为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<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); 
+2

我认为这应该是可接受的答案,因为它解决了问题,并且不需要阻止简短的选项。有一些bug像'option()'应该是'po :: option()',除非你认为'使用命名空间po;'... – rytis 2017-07-31 00:14:12

+0

谢谢,很好。现在修复。 – 2017-08-08 13:58:28

相关问题