#include <boost/scoped_ptr.hpp>
#include <boost/function.hpp>
#include <algorithm>
#include <iostream>
#include <typeinfo>
#include <ostream>
#include <vector>
#include <string>

using namespace std;
using namespace boost;

typedef int KeyEvent;
typedef function<void (const KeyEvent &)> KeyCallback;

struct AbstractCallback
{
    virtual bool equals(const KeyCallback &f) const=0;
    virtual ~AbstractCallback(){}
};

template<typename Callback>
struct ConcreteCallback : AbstractCallback
{
    const Callback &callback;
    explicit ConcreteCallback(const Callback &p_callback) : callback(p_callback) {}
    virtual bool equals(const KeyCallback &f) const
    {
        return callback == f;
    }
};

struct KeyCallbackChecker
{
    scoped_ptr<AbstractCallback> func;
public:
    template<typename Func>
    KeyCallbackChecker(const Func &f) : func(new ConcreteCallback<Func>(f)) {}
    friend bool operator==(const KeyCallback &lhs,const KeyCallbackChecker &rhs)
    {
        return rhs.func->equals(lhs);
    }
    friend bool operator==(const KeyCallbackChecker &lhs,const KeyCallback &rhs)
    {
        return rhs==lhs;
    }
};

void func1(const KeyEvent &)
{
    cout << "func1" << endl;
}

void func3(const KeyEvent &)
{
    cout << "func3" << endl;
}

class func2
{
    int data;
public:
    explicit func2(int n) : data(n) {}
    friend bool operator==(const func2 &lhs,const func2 &rhs)
    {
        return lhs.data==rhs.data;
    }
    void operator()(const KeyEvent &)
    {
        cout << "func2, data=" << data << endl;
    }
};

struct Caller
{
    template<typename F> void operator()(F f)
    {
        f(1);
    }
};

class Callbacks
{
    vector<KeyCallback> v;
public:
    void register_callback(const KeyCallback &callback)
    {
        v.push_back(callback);
    }
    void unregister_callback(const KeyCallbackChecker &callback)
    {
        vector<KeyCallback>::iterator it=find(v.begin(),v.end(),callback);
        if(it!=v.end())
            v.erase(it);
    }
    void call_all()
    {
        for_each(v.begin(),v.end(),Caller());
        cout << string(16,'_') << endl;
    }
};

int main(int argc,char *argv[])
{
    Callbacks cb;
    cb.register_callback(func1);
    cb.register_callback(func2(1));
    cb.register_callback(func2(2));
    cb.register_callback(func3);
    cb.call_all();

    cb.unregister_callback(func2(2));
    cb.call_all();
    cb.unregister_callback(func1);
    cb.call_all();

    return 0;
}
