2012-08-02 41 views
2

我有在一個選項的情況下,升壓program_options(v1_49)()中的問題定義爲構成,也隱式的()。我的意圖是實現類似於perl的-D選項,以便您可以執行-D或-Dname並多次使用它。我options_description是:與構成()和implicit_value升壓program_options()不是「組成的」

( "debug,D", 
    bpo::value<vector<string> >() 
     ->composing() 
     ->implicit_value(vector<string>(1,"1")), 
    "Set debug level." 
), 

這似乎在大多數情況下工作正常,但每當-D沒有值出現在命令行中,所有早期值都被清除,例如:

$ ./a.out -D abc -D 255 -D xyz 
variables_map["debug"] = {"abc", "255", "xyz"} 

$ ./a.out -D -D 255 -D xyz 
variables_map["debug"] = {"1", "255", "xyz"} 

$ ./a.out -D abc -D -D xyz 
variables_map["debug"] = {"1", "xyz"} 

$ ./a.out -D abc -D 255 -D 
variables_map["debug"] = {"1"} 

我想我明白爲什麼會發生這種情況,隱式值{「1」}會替換現有的矢量而不是添加到它。有什麼我可以做得到這個工作,或者是boost :: program_options的限制嗎?

+0

您可以嘗試只具有'的std :: string'內含價值,而不是一個'的std :: VECTOR'之一。 – Xeo 2012-08-07 18:42:33

+0

不確定你的意思,隱式值的類型必須與值的類型匹配。如果不是,則該語句不會編譯。 – user9645 2012-08-10 12:00:20

+0

那麼我在'boost/program_options/detail/value_semantic.hpp:xparse()'中發現了破損的代碼:在'value_store = m_implicit_value;'的情況下,沒有'm_composing == true'的檢查。任何人都可以幫助建議一些方法來追加'value_store'而不是分配給它? – user9645 2012-08-17 19:42:07

回答

2

這是一個解決方法,不需要修改助推源。如果將解析和存儲任務分開,則可以修改中間選項的向量boost::program_options::parsed_options。矢量的每個元素包含std::string鍵和值的std::vector<std::string>。解決方法依賴於這樣的事實:對於隱式值,該值的向量爲空。如果我們掃描parsed_options隱式的價值觀和明確地爲它們分配一個值,那麼他們就不會破壞相同鍵的以前的值。這裏的工作代碼:

#include <iostream> 
#include <string> 
#include <vector> 
#include <boost/foreach.hpp> 
#include <boost/program_options.hpp> 

namespace po = boost::program_options; 

namespace std { 
    // This overload is needed to use composed options. 
    static std::ostream& operator<<(
     std::ostream& os, 
     const std::vector<std::string>& v) { 
     os << '{'; 
     BOOST_FOREACH(const std::string& s, v) { 
     if (&s != &*v.begin()) 
      os << ", "; 
     os << '"' << s << '"'; 
     } 
     os << '}'; 
     return os; 
    } 
} 

int main(int argc, char *argv[]) { 
    po::options_description desc("Allowed options"); 
    desc.add_options() 
     ("debug,D", 
     po::value<std::vector<std::string> >() 
     ->composing() 
     ->implicit_value(std::vector<std::string>(1,"1")), 
     "Set debug level."); 

    // Just parse the options without storing them in the map. 
    po::parsed_options parsed_options = po::command_line_parser(argc, argv) 
     .options(desc) 
     .run(); 

    // Implicit option values are empty, replace with default value. 
    BOOST_FOREACH(po::option& o, parsed_options.options) { 
     if (o.string_key == "debug" && o.value.empty()) 
     o.value.push_back("1"); // default value is "1" 
    } 

    // Now store and earlier values aren't clobbered. 
    po::variables_map vm; 
    po::store(parsed_options, vm); 
    po::notify(vm); 

    std::cout << "variables_map[\"debug\"] = " 
      << (vm.count("debug") ? 
       vm["debug"].as<std::vector<std::string> >() : 
       std::vector<std::string>()) 
      << '\n'; 
    return 0; 
} 

而這裏的那些相同的測試用例:

$ ./a.out -D abc -D 255 -D xyz 
variables_map["debug"] = {"abc", "255", "xyz"} 

$ ./a.out -D -D 255 -D xyz 
variables_map["debug"] = {"1", "255", "xyz"} 

$ ./a.out -D abc -D -D xyz 
variables_map["debug"] = {"abc", "1", "xyz"} 

$ ./a.out -D abc -D 255 -D 
variables_map["debug"] = {"abc", "255", "1"} 
+0

非常感謝,這是比修改boost代碼更好的方法,特別是當我真的不知道我在那裏做什麼時...... – user9645 2013-05-28 18:18:55

0

好了,我終於想通了,似乎爲我工作的解決方案。這將是很好,如果可能有從別人流利的一些獨立覈查boost::program_options,但顯然沒人似乎知道或在意它。

下面是boost_1_49_0,將允許一個選項是既構成(),也有一個implicit_value()補丁。

diff -Naur old/boost/program_options/detail/value_semantic.hpp new/boost/program_options/detail/value_semantic.hpp 
--- old/boost/program_options/detail/value_semantic.hpp 2010-07-12 03:14:14.000000000 -0400 
+++ new/boost/program_options/detail/value_semantic.hpp 2012-08-17 16:31:03.000000000 -0400 
@@ -154,6 +154,28 @@ 
     } 
    } 

+ // Helper function to copy a non-vector implicit value into the 
+ // tokens vector. 
+ template<class T, class charT> 
+ void get_implicit_tokens(std::vector<std::basic_string<charT> >& vs, 
+        const boost::any& a, 
+        T*, long) { 
+  const T va = boost::any_cast<const T>(a); 
+  vs.push_back(boost::lexical_cast<std::basic_string<charT> >(va)); 
+ } 
+ 
+ // Helper function to copy a vector implicit value into the 
+ // tokens vector. 
+ template<class T, class charT> 
+ void get_implicit_tokens(std::vector<std::basic_string<charT> >& vs, 
+        const boost::any& a, 
+        std::vector<T>*, int) { 
+  const std::vector<T> va = boost::any_cast<const std::vector<T> >(a); 
+  for (unsigned i = 0; i < va.size(); i++) { 
+   vs.push_back(boost::lexical_cast<std::basic_string<charT> >(va[i])); 
+  } 
+ } 
+ 
    template<class T, class charT> 
    void 
    typed_value<T, charT>:: 
@@ -164,7 +186,14 @@ 
     // value, then assign the implicit value as the stored value; 
     // otherwise, validate the user-provided token(s). 
     if (new_tokens.empty() && !m_implicit_value.empty()) 
-   value_store = m_implicit_value; 
+   if (m_composing) { 
+    // Attempt to append the implicit value. 
+    std::vector<std::basic_string<charT> > vs; 
+    get_implicit_tokens(vs, m_implicit_value, (T*)0, 0); 
+    validate(value_store, vs, (T*)0, 0); 
+   } else { 
+    value_store = m_implicit_value; 
+   } 
     else 
      validate(value_store, new_tokens, (T*)0, 0); 
    }