2012-08-02 6 views
2

composing() 및 implicit()으로 정의 된 옵션의 경우 boost program_options (v1_49)에 문제가 있습니다. 제 의도는 perl과 비슷한 -D 옵션을 구현하여 -D 또는 -Dname을 사용하여 여러 번 사용할 수 있도록하는 것입니다.composing() 및 implicit_value()가있는 program_options가 "작성되지 않음"

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

이 대부분의 경우에서 확인을 작동하는 것 같다,하지만 값 -D 명령 줄에 나타날 때마다, 이전의 모든 값은 예를 들어, 삭제됩니다 : 내 options_description이다

$ ./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

당신은 대신'표준의 단지'표준 : string' 암시 값을 갖는 시도 할 수 있습니다 : 하나 vector'. – Xeo

+0

암시적인 값의 유형이 값의 유형과 일치해야한다는 것은 무슨 뜻인지 확실치 않습니다. 그렇지 않으면 명령문이 컴파일되지 않습니다. – user9645

+0

글쎄,'boost/program_options/detail/value_semantic.hpp : xparse()'에서 깨진 코드를 발견했다.'value_store = m_implicit_value;'가있는 경우'm_composing == true'에 대한 검사가 없다. 누구든지 그것에 할당하는 것이 아니라 'value_store'에 추가 할 수있는 방법을 제안 할 수 있습니까? – user9645

답변

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

대단히 감사합니다. 부스트 코드를 수정하는 것보다 더 좋은 방법입니다. 특히 내가 현재하고있는 일을 실제로 알지 못하는 경우에는 더욱 그렇습니다. – user9645

0

글쎄, 결국 나에게 맞는 솔루션을 찾았습니다. 가능한 경우 누군가에 유창한 독자로부터 독립적 인 검증을받는 것이 좋겠지 만 분명히 아무도 그 사실을 알거나 신경 쓰지 않는 것처럼 보입니다.

다음은 boost_1_49_0에 대한 패치로, composing()과 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); 
    }