program_optionsの使い方

boostには、program_optionsという、コマンドライン引数やwindows iniファイルのパースに使えるライブラリがある。便利なので、使い方メモ。
main.cpp

/*! g++ -g main.cpp -l boost_program_options
 */

#include <boost/program_options.hpp>
#include <string>
#include <fstream>
#include <iostream>
#include <vector>

namespace po = boost::program_options;
using namespace std;


string configFile;
double x;

void func(const vector<string>& args, const bool help = false){
  double y;
  string s;

  po::options_description opt("options for func");
  opt.add_options()
    ("func.y", po::value<double>(&y), "a double value")
    ("func.s", po::value<string>(&s), "a string value")
    ;

  if(help){
    cout << opt << endl;
    return;
  }

  po::variables_map vm;
  po::store(po::command_line_parser(args).options(opt).allow_unregistered().run(), vm);

  ifstream ifs(configFile.c_str());
  po::store(po::parse_config_file(ifs, opt, true), vm);

  po::notify(vm);

  cout << "y:" << y << endl
       << "s:" << s << endl;
}

int main(int argc, char* argv[]){
  po::options_description optCmdOnly("generic options");
  optCmdOnly.add_options()
    ("help,h",      "produce this help message.")
    ("config,c", po::value<string>(&configFile)->default_value("test-program-options.ini"),   "configuration file")
    ;

  po::options_description optCommon("config file common options");
  optCommon.add_options()
    ("x", po::value<double>(&x), "common value")
    ;

  po::options_description optCmd;
  optCmd.add(optCmdOnly).add(optCommon);

  po::parsed_options parsed = 
    po::command_line_parser(argc, argv).options(optCmd).allow_unregistered().run();

  vector<string> additionalOptions =
    po::collect_unrecognized(parsed.options, po::include_positional);

  po::variables_map vm;
  po::store(parsed, vm);
  po::notify(vm);

  if (vm.count("help")) {
    cout << optCmd << endl;
    func(additionalOptions, true);
    return 0;
  }



  ifstream ifs(configFile.c_str());
  po::store(po::parse_config_file(ifs, optCommon, true), vm);
  po::notify(vm);

  func(additionalOptions, false);

  cout << "x:" << x << endl;
  return 0;  
}

test-program-options.ini

x=	1.0

[func]
y=	2.0
s=	abcd
  • boost_program_optionsをリンクする必要がある(ヘッダのインクルードだけでは使えない)
  • options_descriptionクラスで、オプション項目を登録
    • 変数のポインタを渡しておくと、適切な型に変換した上で、その変数にオプションの値を登録してくれる。
    • デフォルト値も登録できる。
    • 自動で生成されるヘルプのメッセージもここで登録。
  • command_line_parserクラスのコンストラクタにコマンドライン引数を渡して初期化
  • command_line_parserクラスに options_descriptionを登録
  • command_line_parserクラスの allow_unregisteredで、登録されていないオプションを「スルーしろ」と指令(デフォルトでは例外を投げる)
  • command_line_parserクラスのrunで、パース。parsed_optionsクラスのインスタンスが返る。
  • collect_unrecognizedで、未パースコマンドライン引数を取得。これは、後続の関数等に渡して再利用出来る。
  • parse_config_fileで、iniファイルをパース。
    • プログラムの中でのオプションの名前は.となる。

実行結果

bash-3.2$ ./a.out --help

generic options:
  -h [ --help ]                         produce this help message.
  -c [ --config ] arg (=test-program-options.ini)
                                        configuration file

config file common options:
  --x arg               common value

options for func:
  --func.y arg          a double value
  --func.s arg          a string value

ostreamに流すと、ヘルプメッセージになる。

bash-3.2$ ./a.out
y:2
s:abcd
x:1

ini ファイルのパース結果

bash-3.2$ ./a.out --x 10 --func.y 200 --func.s 1234567
y:200
s:1234567
x:10
bash-3.2$ 

先にパースされた値が優先される。