タイトルで定義されている問題に遭遇しました。のインスタンスを作成し、options_description
それを使用するアプリケーションがありますadd_options()
。例のように:
options_description desc;
desc.add_options()
("help", "produce help")
("optimization", value<int>()->default_value(10), "optimization level")
;
optimization
私の質問は、この呼び出しの後のデフォルト値をどのように変更できるかということです。これも可能ですか?ドキュメントは私にはかなり曖昧に見えます。私が理解していることから、質問はvalue_semantic
、括弧内の2番目のパラメーターと同様に、任意の値のセマンティックに一般化できます。
動機
これは不可能かもしれないと感じます。そこで、そのような機能に対する私の動機を示したいと思います。たぶん私の意図したデザインに欠陥があるので、何か他のものを提案することができます。
非常によく似たタスクを実行し、かなりの数のパラメーターとスイッチを共有するプログラムがいくつかあります。共通パラメーターを別の基本クラスにリファクタリングできると思いました。私は、同様の方法でコマンドライン解析をリファクタリングできると思います。boost::program_options
私の考えでは非常にうまく機能します。options_description
基本クラスのプライベートプロパティとしてインスタンスを構築し、そこに共通のオプションを追加します。次に、初期化時に派生クラスadd_options()
で、このオブジェクトを再度実行して、より具体的なオプションを追加します。これは非常にきれいに見え、私はそれをかなり速く動作させました。
次に、すべての派生クラスに共通のオプションがあることに気付きましたが、デフォルト値が異なると非常に便利です。つまり、出力ファイルの名前。app1がapp1.out、app2-app2.outなどになるようにします。
もちろん、出力ファイル名オプションをadd_options
派生クラスに移動することはできますが、意味的にもデフォルト値を除いてすべて同じであるため、愚かで冗長なようです。もう1つの回避策は、基本クラスのデフォルト値を辞任し、派生クラスの解析後の手順で、オプションが設定されているかどうかを確認し、(デフォルトの)値を手動で適用することです。ただし、意図した機能がライブラリ自体に実装されているように見えるため、これも冗長に見えます。
コード例を提供して、後でまたは要求に応じてより良く感じることができるようにします。しかし、私のアプローチはかなり明確だと思います。
編集-コード例 それはロブの答えの後に書かれたので、私は命名規則の範囲内にとどまろうとしました。
ベース-解析を実行し、最適化レベルを整数として設定できます。
#include <boost/program_options.hpp>
namespace po = boost::program_options;
class BaseClass {
public:
BaseClass::BaseClass();
virtual int parse(const int argc, char** argv);
private:
po::options_description m_desc;
po::variables_map vm;
int optimization_level;
};
BaseClass::BaseClass():
m_desc()
{
m_desc.add_options()
("help", "produce help")
("optimization", value<int>()->default_value(10), "optimization level")
;
}
int BaseClass::parse(const int argc, char** argv)
{
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
if (vm.count("help")) { std::cout << desc << "\n"; return 1; }
optimization_level = vm["optimization"].as<int>();
return 0;
}
オプションで派手なことを実行できる高度に最適化されたバージョン:
class HighlyOptimizedClass : public BaseClass {
public:
HighlyOptimizedClass();
virtual int parse(const int argc, char** argv);
private:
bool fancy_optimizations;
};
HighlyOptimizedClass(): BaseClass() {
m_desc.add_options()
("fancy,f", po::value<bool>()->zero_tokens(), "perform fancy optimizations")
;
}
HighlyOptimizedClass::parse(const int argc, char** argv)
{
int ret = BaseClass::parse(argc, argv); //execute base function
if( ret ) return ret; //return if it didnt succed
if ( vm.count("fancy") ) fancy_optimizations = 1; // non-base stuff
return 0;
}
詳細なデバッグをオンにできる最適化されていないバージョン:
class NonOptimizedClass : public BaseClass {
public:
NonOptimizedClass();
virtual int parse(const int argc, char** argv);
private:
bool verbose_debug;
};
NonOptimizedClass(): BaseClass() {
m_desc.add_options()
("verbose,v", po::value<bool>()->zero_tokens(), "genrates TONS of output")
;
}
NonOptimizedClass::parse(const int argc, char** argv)
{
int ret = BaseClass::parse(argc, argv); // execute base function
if( ret ) return ret; // return if it didnt succed
if ( vm.count("verbose") ) verbose_debug = 1; // non-base stuff
return 0;
}
縦に圧縮してみましたが、とにかく長くなりました=/。船外に出たらごめんなさい。同様に、例は明確で自己完結型です。
はBaseClass
ほとんどすべてをセットアップし、一般的なものを解析します。派生クラスは、コンストラクターとオーバーロード解析に独自のオプションを追加します。それらはベースパーサーを実行し、エラーをチェックします。これも機能し--help
ます。
ここで重要なのは、各派生物の最適化のデフォルト値を変更することです。の場合は非常に低く、の場合はNonOptimizedClass
非常に高く設定すると便利ですOptimizedClass
。