d:id:hecomi:20110119にてコマンドライン引数をstd::mapに格納する手段を紹介しましたが,boost::program_optionsを使うともっと簡単にできます.またboost::program_optionsを使えばコマンドラインオプションの解析も容易に行うことができます.
はじめに
MSVCを使っている方はDownload Boost Library Here - BoostProからInstallerをダウンロードして,program_optionsのビルド済みライブラリを導入することが条件となります.boost::program_optionsはヘッダオンリでは動きません.
使い方
一通りの使い方をまとめてみました.
#include <iostream> #include <string> #include <vector> #include <fstream> #include <boost/program_options.hpp> using namespace std; using namespace boost::program_options; int main(int argc, char* argv[]) { // オプションの定義を行う // 後でマージ出来る options_description options1("オプション群1"); options_description options2("オプション群2"); options_description options3("オプション群3"); options_description options4("オプション群4"); // オプションは add_options() 以降に operator() を連結させて追加 // 「,」の手前に正式名,後ろに省略名を記述(省略可) options1.add_options() ("option1", "オプション1") ("option2,b", "オプション2") ; // option=*** で受け取る値の型を設定できる. // また default_value でデフォルト値も設定可 options2.add_options() ("option3,c", value<int>(), "オプション3") ("option4,d", value<string>(), "オプション4") ("option5,e", value<int>()->default_value(10), "オプション5") ; // option=*** の値を受け取る変数を指定もできる. int option6; string option7; options3.add_options() ("option6,f", value<int>(&option6), "オプション6") ("option7,g", value<string>(&option7), "オプション7") ; // 同じオプションを複数使って格納することも出来る options4.add_options() ("option8", value<vector<string> >(), "オプション8") ; // オプションの定義をマージ出来る options1.add(options2).add(options3); // オプションの値を読み込む変数 variables_map values; // 色々な例外をキャッチできる(例はcatchブロック内に記述) try { // parse_command_line でコマンドライン引数をパースし, // この結果を store で variable_maps に格納する store(parse_command_line(argc, argv, options1), values); // コマンドライン引数だけでなく, // 外部ファイルからもオプションを読み込むことが出来る. // この際は parse_config_file を用いてパースする. ifstream ifs("config.txt"); store(parse_config_file(ifs, options4), values); // notify を呼び出すことで values に値が格納される notify(values); // オプションの有無は count で調べる if (!values.count("option1") && !values.count("option2")) { // options_description は標準出力に投げることが出来る cout << options1 << endl; cout << options4 << endl; } if (values.count("option1")) { cout << "option1 が指定されました" << endl; } if (values.count("option2")) { cout << "option2 が指定されました" << endl; } // as<型名>()で値を取り出すことが出来る cout << "option3: " << values["option3"].as<int>() << endl; cout << "option4: " << values["option4"].as<string>() << endl; cout << "option5: " << values["option5"].as<int>() << endl; // 変数で受け取ったものには勿論値が格納されている cout << "option6: " << option6 << endl; cout << "option7: " << option7 << endl; // 複数データを受け取った物も使用可 cout << "option8: "; vector<string> option8( values["option8"].as<vector<string> >() ); for (vector<string>::iterator it = option8.begin(); it != option8.end(); ++it) { cout << *it << " "; } cout << endl; } catch (exception &e) { // 格納されていないのにも関わらず values["***"] を呼ぶと, // boost::bad_any_cast: failed conversion using boost::any_cast // が表示される. // 定義していないオプション --*** を呼ぶと, // unknown option *** // が表示される. cout << e.what() << endl; } return 0; }
結果
コマンドライン引数を与えない場合
オプション群1: --option1 オプション1 -b [ --option2 ] オプション2 オプション群2: -c [ --option3 ] arg オプション3 -d [ --option4 ] arg オプション4 -e [ --option5 ] arg (=10) オプション5 オプション群3: -f [ --option6 ] arg オプション6 -g [ --option7 ] arg オプション7 オプション群4: --option8 arg オプション8
ちょっとずれちゃってますね.
コマンドライン引数を与えた場合
コマンドライン引数 | -b -c 1234 -d hoge -f 2345 -g fuga |
---|
入力ファイル:
# config.txt # 「#」はコメントの「//」にあたる option8 = str1 # 1つ目 option8 = str2 # 2つ目もおk option8 = str3 # 3つ目 option8 = str4 # 4つ目 option8 = str5 # 何個でも追加できる
結果:
option2 が指定されました option3: 1234 option4: hoge option5: 10 option6: 2345 option7: fuga option8: str1 str2 str3 str4 str5
素晴らしい!