はじめに
C/C++ における イベントハンドラの書き方について,定石を整理してみた.
前提
以下のようなコードがあるとする.
#include <iostream>
typedef enum {START, STOP} COMMAND;
void check (COMMAND command) {
std::cout << (int) command << " is called" << std::endl;
}
int main (int argc, char *argv[])
{
check (START);
check (STOP);
return 0;
}
出力結果は以下のようになる.
0 is called
1 is called
この出力結果は以下のようにしたい.
start is called
stop is called
方法
switch を使う
一番単純な方法は, switch をつかって, 表示を分岐する
void onStart () { std::cout << "start is called" << std::endl; }
void onStop () { std::cout << "stop is called" << std::endl; }
void check (COMMAND command) {
switch (command) {
case START:
onStart ();
break;
case STOP:
onStop ();
break;
}
}
};
関数ポインタ配列を使う
別の定石は, 関数ポインタ配列をつかう.
#include <iostream>
typedef enum {START, STOP} COMMAND;
void onStart () { std::cout << "start is called" << std::endl; }
void onStop () { std::cout << "stop is called" << std::endl; }
typedef void (*HANDLER) ();
static HANDLER handle_tbl[2] = {&onStart, &onStop};
void check (COMMAND command) {
handle_tbl[command] ();
}
lambda をつかう
関数テーブルに関数を登録するために, 関数を作成する必要があるけれども, 一行なので, 関数を作成するのは面倒.
そんなときは,c++11 からつかえるようになったラムダ式を利用する.
#include <iostream>
#include <functional>
typedef enum {START, STOP} COMMAND;
static std::function<void ()> handle_tbl[2] = {
[] (){ std::cout << "start is called" << std::endl;},
[] (){ std::cout << "stop is called" << std::endl;}
};
void check (COMMAND command) {
handle_tbl[command] ();
}
int main (int argc, char *argv[])
{
check (START);
check (STOP);
return 0;
}
やっぱり, これからは関数型の時代だよね!
Special Thanks
この記事によると, switch 型と関数テーブル型では, スピードは変わらないとか.
委譲をつかう方法もある (Strategy Pattern)
C++11 の方法.