メモの日々


2007年07月03日(火) [長年日記]

[c++] boost::program_options を使う

設定ファイルの読み込み処理を作りたくて、boost::program_optionsが使えそうなので試してみた。boost::program_optionsはどちらかというとプログラムの起動オプション処理を作るためのライブラリみたいなんだけれど。

サンプルプログラム

動かしてみたプログラムをメモ。

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

namespace po = boost::program_options;

int main(int argc, char* argv[]) {
    // options_descriptionにオプションを定義していく
    po::options_description options("オプション");
    po::options_description command_line("コマンドライン");
    po::options_description config_file("設定ファイル");

    //--- オプションの定義は、operator()をどんどん繋げて書くみたい ---

    command_line.add_options()
        // 値を持たないオプション
        ("help", "ヘルプの表示")
    ;

    std::string option3_value;
    config_file.add_options()
        // オプションの型を指定できる
        ("option1", po::value<int>(), "オプションその1")
        // デフォルト値を指定できる
        ("option2", po::value<std::string>()->default_value("デフォルト値"),
         "オプションその2")
        // オプションを格納する変数(option3_value)を指定できる
        ("option3", po::value<std::string>(&option3_value),
         "オプションその3")
        // 複数指定可能なオプションを作れる
        ("option4", po::value<std::vector<std::string> >(),
         "オプションその4")
    ;

    // オプション定義を合成することができる
    options.add(command_line).add(config_file);

    // ここにオプションの値が読み込まれる
    po::variables_map vm;

    try {
        // command_lineのオプションをparse_command_lineを使ってパースし、
        // 結果をvmに格納する
        po::store(po::parse_command_line(argc, argv, command_line), vm);

        // config_fileのオプションをparse_config_fileを使ってパースし、
        // 結果をvmに格納する
        std::ifstream ifs("config.txt");
        po::store(po::parse_config_file(ifs, config_file), vm);

        // これを呼び出さないと、上で設定したoption3_valuesに値がセットされない
        po::notify(vm);

        // オプションの有無はcount()でチェックするのが正しい?
        if (vm.count("help") || !vm.count("option1") || !vm.count("option3")) {
            // ヘルプの表示
            std::cout << options << "\n";
            return 1;
        }

        std::cout << "option1: " << vm["option1"].as<int>() << "\n";
        std::cout << "option2: " << vm["option2"].as<std::string>() << "\n";
        std::cout << "option3: " << vm["option3"].as<std::string>() << "\n";
        std::cout << "option3_value: " << option3_value << "\n";
        std::vector<std::string> option4
            = vm["option4"].as<std::vector<std::string> >();
        std::cout << "option4 size: " << option4.size() << "\n";
    } catch (std::exception &e) {
        std::cout << e.what() << "\n";
    }
}

ビルド方法

ビルドする際は、次のようにしてboostのライブラリをリンクする必要がある。

g++ option.cpp -lboost_program_options

実行結果

ビルドできたら、config.txt を次のように

$ cat config.txt
# 行頭に#を付けるとコメントを書けるみたい
option1 = 100 # 行の途中からでもコメント書けた
#option2 = nya-
option3 = wanwan
option4 = gao-
option4 = e-n
# option5 = wahahaha

作っておくと、実行結果は次のようになる。

$ ./a.out
option1: 100
option2: デフォルト値
option3: wanwan
option3_value: wanwan
option4 size: 2

ヘルプの表示

ヘルプ表示は次のような感じ。

$ ./a.out --help
オプション:

コマンドライン:
  --help                 : ヘルプの表示

設定ファイル:
  --option1 arg                       : オプションその1
  --option2 arg (=デフォルト値) : オプションその2
  --option3 arg                       : オプションその3
  --option4 arg                       : オプションその4

デフォルト値に日本語を使ったら、ヘルプの表示がずれてしまった。

その他

あと、試してないけれど、「po::notify(vm);」のタイミングで実行されるコールバック関数を各オプションに設定できるみたい。

参考

やること

  • 入庫
  • スーツをクリーニング屋へ
  • ズボンを洗う