ほげたつブログ

プログラムとアニメーションをかじって生きてる

Visual Studio 2013で可変長テンプレートが対応されたのでdelegateのようなものを作ってみた

カッとなってやった。

template <class T, typename... Args>
class Delegate {
private:
    typedef void (T::*Func)(Args... args);
    std::list<std::tuple<T*, Func> > _funcs;

public:
    void add(T* pObj, Func func) {
        assert(!isExists(pObj, func));
        _funcs.push_back(std::make_tuple(pObj, func));
    }

    void remove(T* pObj, Func func) {
        for (auto it = _funcs.begin(); it != _funcs.end(); ++it) {
            if (pObj == std::get<0>(*it) && func == std::get<1>(*it)) {
                _funcs.erase(it);
                break;
            }
        }
    }

    void clear() {
        _funcs.clear();
    }

    bool isExists(T* pObj, Func func) {
        for (auto it = _funcs.begin(); it != _funcs.end(); ++it) {
            if (pObj == std::get<0>(*it) && func == std::get<1>(*it)) {
                return true;
            }
        }
        return false;
    }

    void call(Args... args) {
        for (auto it = _funcs.begin(); it != _funcs.end(); ++it) {
            auto pObj = std::get<0>(*it);
            auto func = std::get<1>(*it);
            (pObj->*func)(args...);
        }
    }
};

こんな感じに使う。

class Test {
public:
    void foo(int v1, float v2) {}
    void bar(int v1, float v2) {}
};

Test t;
Delegate<Test, int, float> d;
d.add(&t, &Test::foo);
d.add(&t, &Test::bar);
d.call(1, 2.0f);

同じインスタンスの同じメンバ関数は同時に登録できない。
リストの中身はタプルにしたけどもっと良い方法は無いかな?
もちろんお仕事では使えない。(コンパイラが云々かんぬん)

同じ内容でQiitaにも投稿してる。
http://qiita.com/HogeTatu/items/188eadefe191db822823