Russell Trahan
Russell Trahan

Reputation: 791

() Operator overloading

This question has been asked before but not answered satisfactorily.

I have a class which is acting as an event handler and I would like to have a nice syntax for calling the event handler outside of an event. What this boils down to is overriding the () operator. I currently have

class EventHandler
{
public:
    void Call(void* sender, EventArgs e);

    void operator() (void* sender, EventArg e){ Call(sender, e); }
};

which works fine. I can call the event handler via

EventHandler EH;
EH(nullptr, EventArgs::Empty());

My problem lies in that I usually store the event handler on the heap so I need

EventHandler* EH;
EH(nullptr, EventArgs::Empty());  // error but this is the syntax I'm hoping for

but this can only be done with

EventHandler* EH;
(*EH)(nullptr, EventArgs::Empty());  // no error

How can I override the () operator to have it work with the pointer to the EventHandler object? I have seen some things that look like overloading the ->() operator instead of just the () operator but I haven't been able to make sense of it.

Upvotes: 2

Views: 192

Answers (5)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275976

It is often a good idea to wrap your heap allocation details in a regular type, and use the regular type rather than a pointer.

class EventHandler_Impl {
public:
        void Call(void* sender, EventArgs e);

        void operator() (void* sender, EventArg e){ Call(sender, e); }
};

then we write:

struct EventHandler {
  void operator()(void* sender, EventArg e){ (*pImpl)(sender, e); }
private:
  std::unique_ptr<EventHandler_Impl> pImpl;
};

we have a "regular" type EventHandler that stores a pointer to the "actual" class. It has methods that forward to the pImpl.

The state of this class is just one pointer. It automatically deletes the pImpl when it goes out of scope. The std::unique_ptr has the overhead of a pointer (which you'd store instead), except it destroys the pImpl object when it goes out of scope.

You can make it move-only, or manually implement a copy constructor (adding to the _Impl interface the ability to clone itself).

It is a bit of boilerplate.

You can do away with writing methods in the _Impl by simply writing them in the regular type, and having them access only state through the pImpl pointer if you choose.

Upvotes: 1

dau_sama
dau_sama

Reputation: 4367

You could use another functor as a wrapper, you'd only need to call it in a slightly different way.

struct EventHandlerCaller
{
   void operator() (EventHandler* eh, void* sender, EventArg& e)
   { 
     eh->operator()(nullptr, sender, e);
   }
}

static EventHandlerCaller caller;
EventHandler* EH;
caller(eh, nullptr, EventArgs::Empty());

Upvotes: 0

sfjac
sfjac

Reputation: 7303

"My problem lies in that I usually store the event handler on the heap so I need"

Is there a reason for this? If the EH involves a large amount of state, then perhaps you could build a wrapper class that put the state on the heap but that itself was allocated as an object. This would allow overloading operator()() and getting the desired syntax, while forwarding to the underlying implementation. Basically refactor to a Pimpl in order to get the syntax you want in the objects that you use in your interface.

Upvotes: 2

Vincent
Vincent

Reputation: 646

The operator ->() doesn't exists.

There are two ways to call the operator.

EventHandler* EH;
(*EH)(nullptr, EventArgs::Empty());

or

EventHandler* EH;
EH->operator()(nullptr, EventArgs::Empty());

This works in the same way as the operator= or any other operator

Upvotes: 7

Barry
Barry

Reputation: 304162

You can't. EventHandler* is a pointer to a type, which is simply not callable.

Upvotes: 0

Related Questions