Re: std::map of pointers to member functions

Discussion in 'C++' started by Victor Bazarov, Jul 24, 2003.

  1. "Jonathan Mcdougall" <> wrote...
    > To make a long story short, I need to associate events with pointers
    > to functions. The first idea which came to my mind was
    >
    > enum Event
    > {
    > clicked,
    > moved
    > };
    >
    > typedef void (*Handler)(int);
    >
    >
    > void my_handler(int)
    > {
    > std::cout << "in my handler";
    > }
    >
    >
    > int main()
    > {
    > std::map<Event, Handler> handlers;
    >
    > handlers.insert(std::make_pair(clicked, &my_handler));
    >
    > if ( event_triggered(clicked) )
    > (handlers[clicked])( /*whatever*/ );
    > }
    >
    >
    > I hope this makes sense.
    >
    > Now, the thing is, I need to include member functions too, so I came
    > up with that :
    >
    > template<class Object, class Function> class Handler
    > {
    > private:
    > Object obj_;
    > Function fun_;
    >
    > public:
    > template<class Object, class Function>
    > Handler(Object obj, Function fun)
    > : obj_(obj),
    > fun_(fun)
    > {
    > }
    >
    > void operator()(int whatever)
    > {
    > ((*obj_).*fun_)(whatever);
    > }
    > };
    >
    > But now I am stuck with the std::map, since it cannot accept templates
    > (as I understand).
    >
    > Could anybody show me a way of acheiving the equivalent results?


    Nothing can accept templates. Everything has to eventually boil down
    to become a concrete class or function. Since you cannot store different
    instantiations of your template class 'Handler' in the same map, you need
    to play the polymorphic card:

    #include <map>
    using std::map;

    enum Event { Clicked, Moved };

    class BaseHandler {
    public:
    ~BaseHandler() {}
    virtual void operator()(int whatever) = 0;
    };

    template<class Object> class Handler
    : public BaseHandler {
    public:
    typedef void (Object::*Function)(int);
    private:
    Object* obj_;
    Function fun_;
    public:
    Handler(Object* obj, Function fun)
    : obj_(obj), fun_(fun)
    {
    }

    void operator()(int whatever)
    {
    (obj_->*fun_)(whatever);
    }
    };

    template<class Object> Handler<Object>*
    makeHandler(Object* obj,
    typename Handler<Object>::Function fun) {
    return new Handler<Object>(obj, fun);
    }

    class ClickHandler {
    public:
    void doit(int);
    };

    int main() {
    map<Event, BaseHandler*> myhandlers;
    ClickHandler cH;
    myhandlers[Clicked] = makeHandler(&cH, &ClickHandler::doit);

    // use it and then _delete_ every entry in the map
    }


    I haven't got this to execute, besides, there is no code to use the
    map, but you should get the idea...

    Victor
    Victor Bazarov, Jul 24, 2003
    #1
    1. Advertising

  2. >> But now I am stuck with the std::map, since it cannot accept templates
    >> (as I understand).
    >>
    >> Could anybody show me a way of acheiving the equivalent results?

    >
    >Nothing can accept templates. Everything has to eventually boil down
    >to become a concrete class or function.


    It makes sense, I still have some difficulties understanding, or
    visualizing, templates.

    >Since you cannot store different
    >instantiations of your template class 'Handler' in the same map, you need
    >to play the polymorphic card:
    >
    > #include <map>
    > using std::map;
    >
    > enum Event { Clicked, Moved };
    >
    > class BaseHandler {
    > public:
    > ~BaseHandler() {}
    > virtual void operator()(int whatever) = 0;
    > };
    >
    > template<class Object> class Handler
    > : public BaseHandler {
    > public:
    > typedef void (Object::*Function)(int);
    > private:
    > Object* obj_;
    > Function fun_;
    > public:
    > Handler(Object* obj, Function fun)
    > : obj_(obj), fun_(fun)
    > {
    > }
    >
    > void operator()(int whatever)
    > {
    > (obj_->*fun_)(whatever);
    > }
    > };
    >
    > template<class Object> Handler<Object>*
    > makeHandler(Object* obj,
    > typename Handler<Object>::Function fun) {
    > return new Handler<Object>(obj, fun);
    > }
    >
    > class ClickHandler {
    > public:
    > void doit(int);
    > };
    >
    > int main() {
    > map<Event, BaseHandler*> myhandlers;
    > ClickHandler cH;
    > myhandlers[Clicked] = makeHandler(&cH, &ClickHandler::doit);
    >
    > // use it and then _delete_ every entry in the map
    > }
    >


    Wow.

    It took me a while to integrate it (since I am not very good with
    templates), but it works like a charm, as your solutions always do.

    Thank you,

    Jonathan
    Jonathan Mcdougall, Jul 25, 2003
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. David White
    Replies:
    0
    Views:
    3,078
    David White
    Jul 24, 2003
  2. Peter Jansson
    Replies:
    5
    Views:
    6,272
    Ivan Vecerina
    Mar 17, 2005
  3. Replies:
    1
    Views:
    408
    red floyd
    Dec 21, 2008
  4. Thomas J. Gritzan
    Replies:
    6
    Views:
    999
    James Kanze
    Dec 22, 2008
  5. James Kanze
    Replies:
    0
    Views:
    1,983
    James Kanze
    Dec 21, 2008
Loading...

Share This Page