2012-09-03 10 views
11

最近、boost::program_optionsを使用し始めて、非常に便利であることがわかりました。つまり、良い方法で自分自身をコード化することができなかった欠点が1つあります。boost::program_options::variables_mapで収集されたすべてのオプションについて繰り返して、画面に出力したいと考えています。これは便利な機能になるはずです。新しいオプションや各プログラムを追加するときに関数を更新する必要なく設定されたすべてのオプションをリストすることができます。boost :: program_options:すべてのオプションを繰り返して印刷する

個々のオプションを確認して出力することができますが、上記のように、これは実際のオプションを知らない一般的な解決策になるはずです。私はさらに、variables_mapの内容を反復することができることを知っています。これは単純に拡張されたstd::mapです。次に、格納されたboost::any変数の中のcontainsd型を確認し、.as<>を使用して適切な型に変換し直すことができます。しかし、これは、各タイプについて1つのケースを持つ長いスイッチブロックをコーディングすることを意味します。そして、これは私にとって良いコーディングスタイルのようには見えません。

質問には、これらのオプションを繰り返し処理して出力する方が良いでしょうか?

答えて

5

Visitorパターンを使用するとよいでしょう。残念ながらboost::anyboost::variantのようなビジターパターンをサポートしていません。それにもかかわらず、第三者approachesがあります。

考えられる別の考え方は、タイプハンドラファンクタにマップされた既知タイプのtype_infoのRTTI:createマップを使用することです。

+0

は、リンクやRTTIについての考えをありがとう:

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; } 

使用法(物事の束をおそらくコンパイルエラーがコードにありますが、私は私のコードベースからそれをリッピングし、非typedefed) 。タイプが増えれば管理しなければならないすべてのサポートされているタイプの構造を構築できないようにしたいと考えていましたが、これは不可能なようです。 基本的に、私は型に渡したいと思っていました - もし彼らが 'operator <<'をサポートしていればすべてうまくいきます。そうでなければコンパイルは失敗します。 – shiin

5

前述の@Rostと同様に、ビジターパターンが良い選択です。 POでそれを使用するには、オプションが渡された場合、通知者がboost::variant値の項目を記入するような方法で通知機能を使用する必要があります。セットは別々に保管する必要があります。その後、あなたのセットを繰り返し処理して、boost::apply_visitorを使ってアクション(つまり、印刷)を自動的に処理することができます。訪問者のための

は、実は、私はビジターと一般的なアプローチの使用は、より幅広い作らboost::static_visitor<>

から継承します。

説明を保持するclass MyOptionを作成しました。値はboost::variant、暗黙的、デフォルトなどのその他のオプションは作成しました。テンプレートを使用してPOのように(boost::po::options_add()を参照)、タイプMyOptionのオブジェクトのベクトルを入力します。渡した瞬間に、またはdouble()boosts::varianの初期化では、値のタイプとデフォルトの暗黙のような他のものを入力します。

boost::po::options_descriptionコンテナを埋めるのにVisitorパターンを使用しました。boost::poは、入力コマンドラインを解析するために独自の構造が必要です。塗りつぶし中に、各オプションの通知者を設定します。それが渡される場合、boost::poは自動的に元のオブジェクトのMyOptionを埋め込みます。

po::parsepo::notifyを実行する必要があります。その後、boost :: variantを内部に保持しているので、すでにVisitorパターンでstd::vector<MyOption*>と入力して使用することができます。

このすべてについては何が良いですか?std::vector<MyOption*>を入力するときに、コードにオプションを1回だけ書き込む必要があります。

PS。この方法を使用している場合、notifyerに値のないオプションを設定する問題に直面する場合は、解決策を得るためにこのトピックを参照してください。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の反復子であり、std :: stringとboost :: program_options :: variable_valueのペアになります。後者はboost :: anyです。私は変数の名前をvit-> firstで印刷することができますが、vit-> secondはboost :: anyなので出力するのが簡単ではない、つまり元の型が失われてしまっています。いくつかはstd :: stringとしてキャストしなければならないものもあれば、doubleのようにキャストするものもあります。

ので、変数の値をcoutに、私はこれを使用することができます:私は、私は、コマンドライン/ 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

とにかく印刷しているので、解析するときに元の文字列表現を取得できます。

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

std::vector<std::string> arguments = GetArgumentList(parsed.options); 
// print 
関連する問題