@nyaocat
Boost 勉強会#9
にゃおきゃっと です
 TwitterID : @nyaocat
 趣味プログラマ
 ↓平日はだいたいこの辺のどちらかに居ます↓
伝えたい事
 Boost使おう
Hello World しよう
#include <iostream>
using namespace std;

int main(){
  cout << “Hello, World!” << endl;
}
Hello World しよう
$ g++ hello.cpp –o hello

$ ./hello
Hello, World!
複数回挨拶させたい!
$ ./hello --count 3
Hello, World!
Hello, World!
Hello, World!

こんな感じに
複数回挨拶させたい!
int main(int argc, char *argv[]){
  int hellon = 1;
  if (argc > 2 && strcmp(argv[1], “--count”)==0)
     hellon = atoi(argv[2]);

    for (int i = 0; i < hellon; ++i)
      cout << “Hello, World!” << endl;
}
複数回挨拶させたい!
int main(int argc, char *argv[]){
  int hellon = 1;
  if (argc > 2 && strcmp(argv[1], “--count”)==0)
     hellon = atoi(argv[2]);

    for (int i = 0; i < hellon; ++i)
      cout << “Hello, World!” << endl;
}
--help も付けたくなった
                    ら?
int main(int argc, char *argv[]){
  int hellon = 1;
   if (argc > 1 && strcmp(argv[1],”--help”) == 0){
     cout << “Usage …” << endl;
     exit(0);
 }
  if (argc > 2 && strcmp(argv[1], “--count”)==0)
     hellon = atoi(argv[2]);

…
--hello-c++で
別の挨拶を出したくなったら?
int main(int argc, char *argv[]){
  int hellon = 1;
  char helloMessage []= “Hello, World!”;
   if (argc > 1 && strcmp(argv[1],”--help”) == 0){
     cout << “Usage …” << endl; ここに追加を忘れてないか?
     exit(0);
 }
  if (argc > 2 && strcmp(argv[1], “--count”)==0)
     hellon = atoi(argv[2]);

    if (argc > 2 && strcmp(argv[1], “--hello-c++”)==0)
       helloMessage = “Hello, C++ !”;

…
--hello-c++ と –x の両方に同じ意
     味を持たせたくなったら?
if (argc > 2 &&( strcmp(argv[1], “--hello-c++”)==0
              || strcmp(argv[1], “-x”) == 0) )
--color, -c でカラー表示機能も
                 付けたくなったら?
for (int i = 0; i < argc; ++i){
 if (strcmp(argv[i], “--count”)==0)
     hellon = atoi(argv[i+1]);
 if (strcmp(argv[i],”—color”)==0
     ||strcmp(argv[i],”-c”))
   …;
 if (strcmp(argv[i], “--hello-c++”)==0
              || strcmp(argv[i], “-x”) == 0)
   …;
}
-c –x と指定可能なら
-cx と –xc も許可されるべきだよ
                       ね
for (int i = 0; i < argc; ++i){
 if (strcmp(argv[i], “--count”)==0)
     hellon = atoi(argv[i+1]);
 if (strcmp(argv[i],”—color”)==0
     &&strcmp(argv[i],”-c”))
   …;
 if (strcmp(argv[i], “--hello-c++”)==0
              && strcmp(argv[i], “-x”) == 0)
   …;
 if (strcmp(argv[i], “-cx”) || strcmp(argv[i],”-xc”)
 …….

}
--countは省略-n にしよう
  -n3 とトークンが連結されてて
                       も
            使えるようにしよう
if (………)
   …….
 if (………………………………………………………………………)
   …….
 if (………………………………………………………………………)
   …….
あ、あと –version, -v オプション
も付けて勿論-cvx, -cxv, -xvc, -xvc,-
  vcx,-vxc と全部可能な感じで
if (………)
   …….
 if (………………………………………………………………………)
   …….
 if (………………………………………………………………………)
   …….
 if (………………………………………………………………………)
   …….
 if (………………………………………………………………………)
   …….
 if (………………………………………………………………………)
   ……if (………………………………………………………………………)
   …….
 if (………………………………………………………………………)
   …….
 if (………………………………………………………………………)
   ……
if (………………………………………………………………………)
   …….
 if (………………………………………………………………………)
   …….
 if (………………………………………………………………………)
   ……
if (………………………………………………………………………)
   …….
 if (………………………………………………………………………)
   …….
 if (………………………………………………………………………)
   ……
if (………………………………………………………………………)
   …….
 if (………………………………………………………………………)
   …….
 if (………………………………………………………………………)
   ……
遠からず破綻する
 誰でも知ってる
そこで



Boost::program_options
概要
 コマンドラインオプション解析を簡潔に書ける
 -xvz と –x –v –z 等を受ける事も自動でしてくれる
 カスタマイズ性は高く無いけどそのまま使えるライ
 ブラリ

!ここから
using namespace std;
using namespace boost;
using namespace boost::program_options;
前提
先程の例
options_description opt(“オプション”)
opt.add_options()
 (“help”, “ヘルプ表示”)
 (“count,n”, value<int>(), “挨拶する回数”)
 (“hello-c++,x”, “メッセージをHello,C++ にする”)
 (“color,c”, “カラー表示”)
 (“version,v”, “バージョンを表示”)
先ほどの例
variables_map vm;
store(parse_command_line(argc, argv, opt), vm);
notify(vm);
先ほどの例
int hellon = 1;
if (vm.count(“count”))
  hellon = vm[“count”].as<int>();



for ( int i = 0; i < hellon; ++i )
  cout << “Hello, World!” << endl;
先ほどの例
./hello –x –n2
./hello --count 3
./hello –vcx
./hello –version –hello-c++ -n1

./hello --help
ヘルプ自動生成
if ( vm.count[“help”] )
   cout << opt << endl;

オプション:
--help                    ヘルプを表示
-n [ --count ] arg        挨拶する回数
-x [ --hellp-c++ ]        メッセージをHello,C++ に
-c [ --color ]            カラー表示
-v [ --version ]          バージョン表示
複数の値、デフォルト値

opt.add_options()
  (“option1”, value<int>()->default_value(10), “op1”)
  (“option2”, value<vector<int>>(), “op2”)
  (“option3”, value<int>()->multitoken(), “op3”);
解析した結果を直接代入
int optvar ;

opt.add_options()
  (“option1”, value<int>(&optvar), “op1”)



 notify() 時にoptvar に値を入れてくれる
オプションとペアになってない
          値も扱う
 ./foo --hoge XXX /etc/passwd
オプションとペアになってない
          値も扱う
 ./foo --hoge XXX /etc/passwd




              突然の死
オプションとペアになってない
          値も扱う

 ./foo --hoge XXX /etc/passwd


 /etc/passwd がどのオプションとも結びついてない
オプションとペアになってない
          値も扱う


 positional_option_description を使う
オプションとペアになってない
           値も扱う
 positional_options_description pd;
 pd.add(“input-file", 1);


 ./foo --hoge XXX /etc/passwd
↓
 ./foo --hoge XXX --input-file /etc/passwd


 解決……?
オプションとペアになってない
          値も扱う
 ヘルプメッセージと挙動が食い違う


 じゃあヘルプメッセージを変えれば良い
オプションとペアになってない
 オプションを2つ用意する
               値も扱う
 公開ヘルプ用、実際の処理用

options_description opt(“オプション”)
opt.add_options()
 (“help”, “ヘルプ表示”)

options_description hidden(“処理用”)
hidden.add_options()
   ( opt )
  (“—input-file”, value<int>(), “隠しオプション”)
オプションとペアになってない
          値も扱う
variables_map vm;
store(parse_command_line(argc, argv, hidden), vm);
notify(vm);

if (vm.count(“help”) )
   cout << opt << endl;
•未知のオプションにも対応させ
              る



 ./compiler-wrapper --compiler-option –O2 -lSDL
•未知のオプションにも対応させ
              る



              突然の死
 ./compiler-wrapper --compiler-option –O2 -lSDL
•未知のオプションにも対応させ
              る

 ./compiler-wrapper --compiler-option –O2 -lSDL


 -O, -l を定義してないので不明なオプション例外


 basic_command_line_parser の
   allow_unregistered を使う
•未知のオプションにも対応させ
              る

 ./compiler-wrapper --compiler-option –O2 -lSDL


 -O, -l を定義してないので不明なオプション例外


 basic_command_line_parser の
   allow_unregistered を使う
•未知のオプションにも対応させ
              る

 command_line_parser(argc, argv)
    .options(opt)
    .allow_unregistered()
    .run();
•未知のオプションにも対応させ
              る

 ./compiler-wrapper --compiler-option –O2 -lSDL



 ./compiler-wrapper --compiler-option=“–O2 -lSDL”
他のオプション形式にも対応す
             る
boost::program_options が標準で用意してるのは
   二種類のみ

ロングオプション(ハイフン二個、 --hoge=value 等可
 能)
ショートオプション(ハイフン一個、一文字限定 –
 acxv 可能

ハイフン3つ以上等
他のオプション形式にも対応す
             る
 -fno-rtti とかやりたい
 Windows風に /Z /D とかやりたい
 tar xvzf とかやりたい


 突然の……
他のオプション形式にも対応す
             る
 別に確実に死ぬ訳ではない


 ただ、オプションとして認識されない
(から、適切なオプション設定が無いと死ぬ)

 オプションとして認識させる必要がある


 引数解析前にパーサで前処理させれば良し
他のオプション形式にも対応す
              る
pair<string,string> reg_f (string const& s){
  if ( s.find(“-f”) == 0 )
     if ( s.substr(2, 3) == “no-” )
        return { s.substr(5), string(“false”) };
     else
        return { s.substr(3), string(“true”) };
   else
       return {string(), string()};
}
他のオプション形式にも対応す
             る

 store(command_line_parser(ac,av)
         .options(desc)
         .extra_parser(reg_foo)
         .run(), vm);
他のオプション形式にも対応す
             る


 ./rofi -fno-pants


     ↓

 ./rofi --pants false
他のオプション形式にも対応す
             る
 実はこれでは /D や xvzf には対処できない


 extra_parser は一つのトークン
      ⇒ 一つのオプション、値のペアにするのみ
他のオプション形式にも対応す
              る
 編集した argc argv を渡す


 basic_command_line_parser
      ( int argc, char const* const argv);
 basic_command_line_parser
      ( vector<string> const& args );

 Qi ~!Karma ja~!!
コンフィグファイルを読む
こんなの

[section]
value1 = 123
hoge = true
piyo = ok
# comment
コンフィグファイルを読む
セクション名 . フィールド名になる

options_description opt(“オプション”)
opt.add_options()
 (“section.value1”, value<int>(), “value1”)
 (“section.hoge”, bool_switch(), “hoge”)
 (“section.piyo”, value<string>(), “piyo”);
コンフィグファイルを読む
作成した option がそのまま流用可能
コードも流用可能

ifstream ifs(“a.conf”);
variables_map vm;
store(parse_config_file(ifs, opt), vm);
notify(vm);
環境変数を読む
 流用可能


variables_map vm;
store(parse_envirement(opt, name_mapper), vm);
notify(vm);
環境変数を読む
 name_mapper :: string -> string


オプション引数が渡されるので、
対応する環境変数名を返す

空文字列を返すとそのオプションでは環境変数を
チェックしない
環境変数を読む
 name_mapper :: string -> string


オプション引数が渡されるので、
対応する環境変数名を返す

空文字列を返すとそのオプションでは環境変数を
チェックしない
パーサー
 それぞれの parser は        basic_parsed_options< charT
 >
      を返す

variables_map vm;
store(parse_hogehoge(), vm);
notify(vm);

独自定義のパーサが利用出来る!!
パーサー
(有用なパーサが思いつきませんでした)
Windows対応
 WinMain だと lpCmdLine


 sprit_winmain( lpCmdLine )で
  vector<string> に出来る
Q&A
Q&A
 C++/Tk(仮)から随分変わったね?


Cpptk はライセンス無しだった為使えない事が
   昨日の朝分かりました

突然の死
Q&A
 Getopt, Getopts は?
Q&A
 Getopt, Getopts は?




             突然の死
ありがとうございました
 突然の死は単に例外が投げられる事を示すもので
 あって異常終了ではありません

 Windows風オプション処理等は標準で用意されてい
 た事を発表中にご指摘頂きました

http://www.boost.org/doc/libs/1_49_0/doc/html/boost/
  program_options/command_line_style/style_t.html

Boost jp9 program_options