組み込みマイコンでstd::functionを~

少し落ち着いたので(実際は、やるべき事が山済み状態だけど・・)気になっていた部分をクリーンナップしている。
現在、俺俺フレームワークは、リアルタイムOSの助けを借りない方法で実装を行っているので、一連の長い処理を書く場合などにはコールバックの仕組みを与えている。
C++11 以降、STL には、そのような場合便利で安全な方法が多数用意されている。
しかし、その場合、通常は「stdc++」をリンクする必要があり、その場合、許容出来ない程大量のワークエリアを消費し、実用的では無い場合があった。

さて、コールバック機能を実装する場合、どうしても、「std::function」を使いたい。
・このテンプレートは、非常に強力かつ高機能だが、詳しい使い方は、検索してほしい。
・このテンプレートにする最大の理由は、ラムダ式が使える事で、コールバックの中身を「直」で実装できる。

しかしながら、これを使うとなると、関連する例外処理など他の機能を利用している為、stdc++ ライブラリのリンクが必須となってしまう。
しかし、よく調べると、g++では、「supc++」ライブラリが分離されておりこれをリンクすれば、最低限の消費で済む事が判った。
※「supc++」は「stdc++」ライブラリのランタイム部分のみ。
※例外の外部関数を実装する必要がある。

namespace std {
    void __throw_bad_function_call()
    {
        abort();
    }
}

※コンパイラオプションで例外を禁止していても、これだけはリンクする必要があるようだ。
※これは、「common/stdapi.cpp」に分離してあるので、Makefile にこのソースを追加する必要がある。

コールバック関数の登録で、重要となるのは、たとえば、クラス内からコールバックを設定するような場合だが、普通に書いた場合、「static」な関数しか登録できない。
※それでも別の逃げ方が無い訳では無いが、少し面倒・・
static だと、クラス内の public メンバーなどにアクセス出来ない。
そこで便利なテクニックとして、ラムダ式によるキャプチャー機能を利用する事で、以下のようにクラス内メソッドを呼び出す事が可能となる。

void play_loop_(const char* root, const char* start)
{
    static loop_t t;
    t.start = start;
    if(strlen(start) != 0) {
        t.enable = true;
    } else {
        t.enable = false;
    }
    sdc_.set_dir_list_limit(1);
    sdc_.start_dir_list(root,
        [&](const char* name, const FILINFO* fi, bool dir, void* option) { play_loop_func_(name, fi, dir, option); }, true, &t);
}

上記コードは、オーディオプレイヤーのコードで、ディレクトリーを巡って、オーディオファイルを再生する。
「sdc_.start_dir_list()」で、ファイル情報アクセス時に、設定されたコールバックが起動する。
「play_loop_func_」は、ラムダ式のキャプチャー「[&]」が あり、クラス内のリソースにアクセスする事が出来る。(これは本当に便利だ!)

まとめ:
「std::function」を使う事で、関数オブジェクトの利便性が強化された、これは、C++11以降の恩恵で、かなり大きなトピックと言えるが、組み込みマイコンのような制限されたリソースでもそれを活用できる事が判った事は大きい~

カテゴリー: ソフトウェアー・エンジニアリング, 電子工作な日々 パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください