コマンドライン引数を簡単に取り扱うクラス
コマンドライン引数を取り扱うとき getopt や Boost::program_options 以外に、google-gflags というのを教えてもらった。
http://googlejapan.blogspot.com/2007/07/google-1.html
getopt も Boost::program_options もオプションのリストをあらかじめ作る必要があるが、google-gflags では必要になったら追加する、といった記述ができる。LL 感覚でプログラムを書くときは便利そうだと思い、自分でも遊びで作ってみた。
目標
OPTION_DEFINE(g_numOfData, 123, "num-of-data", "Number of data");
- ↑のようにマクロ感覚で1行で変数、初期値、オプション引数のシンボル、説明文が定義できる
- あとはどこかでうまく処理してくれる
- 実行時引数に --num-of-data 1234 などと指定したら、g_numOfData に代入される
- 実行時引数がなければ初期値が、g_numOfData に代入される
- パースエラー時は定義されているオプションの一覧を表示する
定義を書くと自動的に static なリストに追加されるようにしたいが、リストに追加するコードをどうやって駆動させるか考えてみた。思いついたのは次の2つ。
コンストラクタを利用したデザイン
http://github.com/iwagaki/sandbox/tree/master/OptionParser/
OPTION_INT g_numOfData("num-of-data", "Number of data", 123); int main(int argc, char** argv) { OptionParser::parse(argc, argv); printf("g_numOfData = %d\n", (int)g_numOfData); return 0; }
- OPTION_INT というクラスを作り、コンストラクタで static std::vector<...> OptionParser::m_optionList に登録していく
- main() で parse() を呼ぶと m_optionList に従って解析して、各オブジェクトにオプションの引数を代入する
- 利用する側はオブジェクトに対してアクセスする
- operator T() を定義してあるので、ある程度は通常の型と同じ感覚で読み出せる
難点は、
- OPTION_INT など特別な型を使うのが気持ち悪い
- 暗黙の型変換による読み出しがトリッキーで気持ち悪い
グローバル変数の関数による初期化を利用したデザイン
http://github.com/iwagaki/sandbox/tree/master/OptionParser2/
int& g_numOfData = OptionParser::createOption(123, "num-of-data", "Number of data"); int main(int argc, char** argv) { OptionParser::parse(argc, argv); printf("g_numOfData = %d\n", g_numOfData); return 0; }
- 普通の型で宣言をして、専用関数で初期化することで、static std::vector<...> OptionParser::m_optionList に登録していく
- main() で parse() を呼ぶと m_optionList に従って解析して、各変数の実態に引数を代入する
- 利用する側は普通に変数にアクセスする
難点は、
結論
作るのは楽しかったが、他人と共有するコードでは Boost::program_options を使う。