13

最近使い始めboost::program_optionsましたが、とても便利です。とはいえ、自分自身を適切にコーディングできなかったことが 1 つ欠けています。

boost::program_options::variables_mapで収集されたすべてのオプションを繰り返し処理して、画面に出力したいと思います。これは、新しいオプションを追加するとき、またはプログラムごとに関数を更新する必要なく、設定されたすべてのオプションをリストするために呼び出すだけの便利な関数になるはずです。

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

問題は、これらのオプションを繰り返し処理して出力するより良い方法はないかということです。

4

4 に答える 4

7

@Rostが前述したように、ここではビジターパターンが適切な選択です。POで使用するには、オプションが渡された場合に通知機能が値のセットのエントリを埋めるように、オプションに通知機能を使用する必要がありboost::variantます。セットは個別に保管する必要があります。その後、セットを反復処理し、を使用してアクションを自動的に処理(つまり印刷)することができますboost::apply_visitor

訪問者の場合、boost::static_visitor<>

実際、私はビジターと一般的なアプローチの使用をより広くしました。

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

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

次に、とを実行する必要がpo::parseありpo::notifyます。std::vector<MyOption*>その後、 boost :: Variantを内部に保持しているため、Visitorパターンを介してすでに入力されているものを使用できるようになります。

これらすべての良い点は、を入力するときに、コードにオプション型を1回だけ記述する必要があることですstd::vector<MyOption*>

PS。このアプローチを使用すると、値のないオプションの通知機能を設定する際に問題が発生する場合は、次のトピックを参照して解決策を入手してください。boost -program-options:値のないオプションの通知機能

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));  
于 2012-09-04T17:15:06.350 に答える
5

Visitor パターンを使用するのは良いケースです。残念ながらboost::any、Visitor パターンはサポートしていませんboost::variant。それにもかかわらず、いくつかのサードパーティのアプローチがあります。

もう 1 つの考えられるアイデアは、RTTI を使用することtype_infoです。型ハンドラー ファンクターにマップされた既知の型のマップを作成します。

于 2012-09-03T08:58:28.743 に答える
2

とにかくそれらを印刷するだけなので、解析時に元の文字列表現を取得できます。(コードにコンパイラエラーがある可能性があります。コードベースと型定義されていないものから切り取ったものです)

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
于 2014-09-04T16:14:27.127 に答える
0

今日はまさにこのタイプの問題を扱っていました。これは古い質問ですが、答えを探している人に役立つかもしれません。

私が思いついた方法は、一連の as<...>() を試してから、例外を無視することです。あまりきれいではありませんが、動作するようになりました。

以下のコード ブロックでは、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 などとしてキャストする必要があります。

したがって、変数の値を計算するには、これを使用できます。

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 */ }

コマンドライン/構成ファイルから情報を取得するために使用するタイプは 4 つしかありません。さらにタイプを追加すると、さらに行を追加する必要があります。これが少し醜いことは認めます。

于 2014-09-04T15:33:56.707 に答える