リアクティブシーケンスのフィルタ

先日のリアクティブシーケンスに、filter()メンバ関数を追加してみました。(map()は難しいのでやめました)

#include <iostream>
#include <functional>

template <class T>
class reactive_sequence {
    std::function<void(T)> f_;
    std::function<bool(T)> filterf_;
public:
    template <class F>
    void foreach(F f)
    {
        f_ = f;
    }

    template <class Pred>
    reactive_sequence& filter(Pred pred)
    {
        filterf_ = pred;
        return *this;
    }

    template <class U>
    void reaction(const U& arg)
    {
        if (!filterf_ || filterf_(arg))
            f_(arg);
    }
};

struct Point {
    int x, y;
    Point(int x, int y) : x(x), y(y) {}
};

reactive_sequence<Point> seq;

void click_event(Point p)
{
    seq.reaction(p);
}

void print_ln(Point p)
{
    std::cout << p.x << ',' << p.y << std::endl;
}

int main()
{
    // イベントが発生したときのハンドラ
    seq.filter([](Point p) { return p.x > 0 && p.y > 0; })
       .foreach([](Point p) { print_ln(p); });

    // イベント起動
    click_event({2, 3});
}

出力:

2,3

実際のイベント処理(foreach)とフィルタ処理をリスト処理のように分けられるようになります。

ここでは、有効範囲内のクリック座標のみをイベント処理しています。

この他にも、イベントにエラーが渡される可能性があってそのエラーイベントを単に捨てるような場合は、フィルタで弾けばいいですね。音声処理なんかでも、特定の周波数(?)帯のみ扱うようなコードが、すっきりしそうです。