2012-09-03 2 views
11

최근에 boost::program_options을 사용하기 시작했으며 매우 편리합니다. 즉, 좋은 방법으로 코드를 작성할 수 없었던 한 가지가 있습니다.boost :: program_options : 모든 옵션을 반복하고 인쇄합니다.

boost::program_options::variables_map에 수집 된 모든 옵션을 반복하여 화면에 출력하고 싶습니다. 이것은 편의 기능이되어야하며, 새로운 옵션을 추가하거나 각 프로그램을 추가 할 때 함수를 업데이트 할 필요없이 설정 한 모든 옵션을 나열하기 만하면됩니다.

개별 옵션을 확인하고 출력 할 수 있지만 위에서 말했듯이 이것은 실제 옵션을 알지 못하는 일반적인 해결책이되어야합니다. 또한 variables_map의 내용을 반복 할 수 있다는 것을 알고 있습니다. 확장 된 내용은 단순히 std::map입니다. 그런 다음 저장된 변수에 containsd 유형이 있는지 확인하고 .as<>을 사용하여 해당 유형으로 다시 변환 할 수 있습니다. 그러나 이것은 각 유형에 대해 하나의 케이스가있는 긴 스위치 블록을 코딩하는 것을 의미합니다. 그리고 이것은 나에게 좋은 코딩 스타일처럼 보이지 않습니다.

질문은 이러한 옵션을 반복하고 출력하는 더 좋은 방법이 있습니까?

답변

5

방문자 패턴을 사용하는 것이 좋습니다. 죄송합니다. boost::anyboost::variant과 같은 방문자 패턴을 지원하지 않습니다. 그럼에도 불구하고 제 3 자 approaches이 있습니다.

또 다른 가능한 아이디어는 유형 핸들러 펑터에 매핑 된 알려진 유형의 type_info 인 RTTI : 맵 생성 맵을 사용하는 것입니다.

+0

링크 및 RTTI에 대한 아이디어를 주셔서 감사합니다 . 형식이 증가하면 관리해야하는 모든 지원되는 형식의 구조를 만들지 못하게 할 수 있었으면 좋겠지 만 이는 불가능할 것으로 보입니다. 기본적으로, 나는 형에 건네 주길 원했습니다. 연산자가 'operator <<'를 지원한다면 모든 것이 정상적으로 작동합니다. 그렇지 않으면 컴파일이 실패해야합니다. – shiin

5

@Rost가 이전에 언급했듯이 방문자 패턴은 여기에서 좋은 선택입니다. PO와 함께 사용하려면 옵션이 전달되면 알리미가 boost::variant 값의 항목을 채울 수 있도록 옵션에 알리미를 사용해야합니다. 세트는 별도로 보관해야합니다. 그런 다음 세트를 반복하고 boost::apply_visitor을 사용하여 작업 (즉, 인쇄)을 자동으로 처리 할 수 ​​있습니다. 방문객을위한

은, 사실, 방문객 및 일반 접근 방식의 사용이 더 광범위하게 boost::static_visitor<>

에서 상속합니다.

설명을 포함하는 class MyOption을 작성했으며 암시 적, 기본값 등과 같은 기타 옵션은 boost::variant입니다. 템플릿을 통해 PO 옵션 (boost::po::options_add() 참조)에 대해 PO와 같은 방식으로 MyOption 유형의 객체 벡터를 채 웁니다. 또는 을 boosts::varian t로 전달할 때 값의 유형 및 기본값 (암시 적)과 같은 다른 것들을 채 웁니다.

그 후 컨테이너를 채우기 위해 Visitor 패턴을 사용했습니다. boost::po에는 입력 명령 행을 구문 분석하기위한 구조가 필요하기 때문입니다. 작성하는 동안 각 옵션에 대해 알림을 설정합니다. boost::po이 전달되면 MyOption의 원래 개체가 자동으로 채워집니다.

다음으로 po::parsepo::notify을 실행해야합니다. 그 후 boost :: variant 내부에 visitor 패턴을 통해 이미 채워진 std::vector<MyOption*>을 사용할 수 있습니다.

무엇이 좋을까요? std::vector<MyOption*>을 작성할 때 코드에 한 번만 옵션 유형을 작성해야합니다.

추신. 이 접근법을 사용하는 경우 값이없는 옵션에 대한 알림을 설정하는 문제가 발생하는 경우 솔루션을 얻으려면 다음 주제를 참조하십시오. boost-program-options: notifier for options with no value

PS2. 코드 예 :

std::vector<MyOptionDef> options; 
OptionsEasyAdd(options) 
    ("opt1", double(), "description1") 
    ("opt2", std::string(), "description2") 
... 
; 
po::options_descripton boost_descriptions; 
AddDescriptionAndNotifyerForBoostVisitor add_decr_visitor(boost_descriptions); 
// here all notifiers will be set automatically for correct work with each options' value type 
for_each(options.begin(), options.end(), boost::apply_visitor(add_descr_visitor)); 
+0

철저한 설명에 감사드립니다. 이것은 또한 흥미로운 해결책입니다. 이 방법으로 나는 또한 단순히 옵션 값을 나열 할 때 도움말 출력에 대해 다른 설명을 쉽게 추가 할 수 있습니다. – shiin

0

오늘 저는이 유형의 문제를 처리하고있었습니다. 이것은 오래된 질문이지만 아마도 이것은 대답을 찾는 사람들에게 도움이 될 것입니다.

제가 생각해내는 방법은 < ...>()의 무리를 시도한 다음 예외를 무시하는 것입니다. 그것은 굉장히 예쁘지는 않지만 작동하도록했습니다.

아래 코드 블록에서 vm은 boost program_options의 variables_map입니다. vit은 VM에 대한 iterator로, std :: string과 boost :: program_options :: variable_value로되어 있고, 후자는 boost :: any입니다. 저는 vit-> first로 변수 이름을 출력 할 수 있습니다. 그러나 vit-> second는 boost :: any이기 때문에 출력하기가 쉽지 않습니다. 즉, 원래 유형이 손실되었습니다. 어떤 것은 std :: string으로 캐스팅되어야하고, 어떤 것은 double로 캐스팅되어야한다.

그래서, 변수의 값을를 법원에,이를 사용할 수 있습니다 난 단지 내가 명령 줄/config 파일에서 정보를 얻기 위해 사용하는 4 가지 유형이

std::cout << vit->first << "="; 
try { std::cout << vit->second.as<double>() << std::endl; 
} catch(...) {/* do nothing */ } 
try { std::cout << vit->second.as<int>() << std::endl; 
} catch(...) {/* do nothing */ } 
try { std::cout << vit->second.as<std::string>() << std::endl; 
} catch(...) {/* do nothing */ } 
try { std::cout << vit->second.as<bool>() << std::endl; 
} catch(...) {/* do nothing */ } 

, 내가 더 추가 한 경우 유형을 추가하려면 라인을 추가해야합니다. 나는 이것이 약간 추한 것을 인정할 것이다.

0

어쨌든 출력하기 때문에 구문 분석 할 때 원본 문자열 표현을 잡을 수 있습니다. (가능성이 컴파일러 오류 코드에있다, 나는 내 코드베이스와 가지 않은 typedefed 무리에서 그것을 찢어)

std::vector<std::string> GetArgumentList(const std::vector<boost::program_options::option>& raw) 
{ 
    std::vector<std::string> args; 

    BOOST_FOREACH(const boost::program_options::option& option, raw) 
    { 
     if(option.unregistered) continue; // Skipping unknown options 

     if(option.value.empty()) 
      args.push_back("--" + option.string_key)); 
     else 
     { 
      // this loses order of positional options 
      BOOST_FOREACH(const std::string& value, option.value) 
      { 
       args.push_back("--" + option.string_key)); 
       args.push_back(value); 
      } 
     } 
    } 

    return args; 
} 

사용법 :

boost::program_options::parsed_options parsed = boost::program_options::command_line_parser(... 

std::vector<std::string> arguments = GetArgumentList(parsed.options); 
// print 
관련 문제