読者です 読者をやめる 読者になる 読者になる

boost program optionsを使ってみた。

まずはチュートリアルを読む。

基本的な使い方

基本的な使い方は以下のようになる。

  1. オプションを定義。"help,h"は「--helpと-h」の意味。
  2. argc, argvをパースして定義したオプションと関連付けし、variable_mapを生成。
  3. variable_mapに、定義したオプションが含まれるかをvm.count("hoge")でチェックし含まれていた場合は処理を行う。
namespace po = boost::program_options;

// Declare the supported options.ds
po::options_description desc("Allowed options");
desc.add_options()
    ("help,h", "produce help message");

// Parse arguments and create a variable map.
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);

// Handle argument if included in variable map.
if(vm.count("help")) {
    std::cout << desc << "\n";
    return;
}

バリエーション

引数を取らないもの

("help,h", "produce help message");

実行結果

./optionTest -h
Allowed options:
  -h [ --help ]         produce help message

引数を取るもの

("compression,c", po::value<int>(), "set compression level")

...

if (vm.count("compression")) {
    std::cout << "Compression level was set to "
              << vm["compression"].as<int>() << std::endl;
}

実行結果

optestTset --compression 10
Compression level was set to 10

引数が複数あるもの

./optionTest -c 10 20 30
Compression level was set to 10 20 30

もしくは

./optionTest --compression=10 20 30
Compression level was set to 10 20 30

コード例

desc.add_options()
    ("help,h", "produce help message")
    ("compression,c", po::value<std::vector<int>>(), "set compression level")
    ;

...

if (vm.count("compression")) {
    std::vector<int> v = vm["compression"].as<std::vector<int>>();
    std::cout << "Compression level was set to ";
    std::for_each(v.begin(), v.end(), [](int i){std::cout << i << " ";});
    std::cout << std::endl;
}

引数のみのもの

例えばこういうもの。

./optionTest 10
Compression level was set to 10

コード例

po::options_description desc("Allowed options");
desc.add_options()
    ("help,h", "produce help message")
    ("compression,c", po::value<int>(), "set compression level")
    ;

// Set the positional options
po::positional_options_description p;
p.add("compression", -1);

po::variables_map vm;

// Construct po::command_line_parser and set to positional
// instead of calling the po::parse_command_line.
po::store(po::command_line_parser(argc, argv).
          options(desc).positional(p).run(), vm);

引数が複数あるオプションが複数ある場合

コード例

desc.add_options()
    ("help,h", "produce help message")
    ("compression,c", po::value<std::vector<int>>(), "set compression level")
    ("sampling,s", po::value<std::vector<int>>(), "set sampling rate")
    ;

このような場合はすべての引数にオプション指定が必要になる。

./optionTest -c 10 -c 20 -c 30 -s 10 -s 20
Compression level was set to 10 20 30
Sampling rate was set to 10 20

ただしどちらかにpositionalの設定を行った場合(後述)は、 オプション指定なしのパラメータはすべてpositional設定したものとして扱われる。

// Set the positional options
po::positional_options_description p;
p.add("compression", -1);

実行例

./optionTest -c 10 20 -c 30 -s 10 40
Compression level was set to 10 20 30 40
Sampling rate was set to 10

ドキュメントが不親切かも?

http://www.boost.org/doc/libs/1_57_0/doc/html/program_options/tutorial.html#idp343134496の最後のパラグラフでは、あるべきコードサンプルが抜けているっぽい。

The parsing and storing of values follows the usual pattern, except that we additionally call parse_config_file, and call the store function twice. But what happens if the same value is specified both on the command line and in config file? Usually, the value stored first is preferred. This is what happens for the "--optimization" option. For "composing" options, like "include-file", the values are merged.

急に2回目のstore()呼び出しではparse_config_fileを呼び出すとか文章だけで言われてもなかなかピンと来なかった。

po::variables_map vm;
std::ifstream ifs("example.cfg", std::ios::binary);
po::store(po::command_line_parser(ac, av).
          options(visible).positional(p).run(), vm);
po::store(po::parse_config_file(ifs, config_file_options), vm);
po::notify(vm);

if(vm.count("help")) {
    std::cout << visible << "\n";
    return;
}

せめてこういう感じのがあったら解りやすかったかな。