2010-11-05 48 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

相關問題