C 言語/C++ における イベントハンドラの定石 (switch/ 関数ポインタ配列/lambda)

    はじめに

    C/C++ における イベントハンドラの書き方について,定石を整理してみた.

    [toc]

    前提

    以下のようなコードがあるとする.

    [sourcecode language=”cpp” title=”” ]
    #include
    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; } [/sourcecode]

    出力結果は以下のようになる.

    [sourcecode language=”text” title=”” ]
    0 is called
    1 is called
    [/sourcecode]

    この出力結果は以下のようにしたい.

    [sourcecode language=”text” title=”” ]
    start is called
    stop is called
    [/sourcecode]

    方法

    switch を使う

    一番単純な方法は, switch をつかって, 表示を分岐する

    [sourcecode language=”cpp” title=”” ]
    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; } } }; [/sourcecode]

    関数ポインタ配列を使う

    別の定石は, 関数ポインタ配列をつかう.

    [sourcecode language=”cpp” title=”” ]
    #include

    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] (); } [/sourcecode]

    lambda をつかう

    関数テーブルに関数を登録するために, 関数を作成する必要があるけれども, 一行なので, 関数を作成するのは面倒.

    そんなときは,c++11 からつかえるようになったラムダ式を利用する.

    [sourcecode language=”cpp” title=”” ]
    #include
    #include

    typedef enum {START, STOP} COMMAND;

    static std::function 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; } [/sourcecode]

    やっぱり, これからは関数型の時代だよね!