Events and Delegates – or fun with templates

Were you ever in a situation where you wrote a piece of code, used it, loved it and half a year later you use it again and well, somehow your expectations have risen?
That happened to me with the events of POCO.
If you used them, you are probably famliar with that code:

Poco::BasicEvent<const std::string> ENameChanged;
Poco::BasicEvent<const std::pair<Address, Address> > EAddressChanged;
// first is old, 2nd is new

[...]

void PersonMonitor::add(Person& p)
{
    p.ENameChanged += Poco::Delegate<PersonMonitor, const std::string>(
        this, &PersonMonitor::onNameChanged);
    p.EAddressChanged += Poco::Expire<const std::pair<Address, Address> >(
        (Poco::Delegate<PersonMonitor, const std::pair<Address, Address> >(
            (this, &PersonMonitor::onAddressChanged), 1000);
}

Actually a lot of code just to add a delegate to an event. You need to know the type of the argument and the type of the receiver object. And then you have to wrap an expire object around the delegate only to tell it that the registration should expire in 1000 millisecs. For my taste that’s too much typing work. But it’s a template object, so you always have to specify the type.
But what if you’d use template functions?

template <class TObj, class TArgs>
static Delegate<TObj, TArgs> delegate(
    TObj* pObj,
    void (TObj::*NotifyMethod)(const void*, TArgs&))
{
    return Delegate<TObj, TArgs>(pObj, NotifyMethod);
}

template <class TObj, class TArgs>
static Expire<TArgs> delegate(
    TObj* pObj,
    void (TObj::*NotifyMethod)(const void*, TArgs&),
    Timestamp::TimeDiff expireMillisecs)
{
    return Expire<TArgs>(
        Delegate<TObj, TArgs>(pObj, NotifyMethod),
        expireMillisecs);
}

Now the compiler can determine the type of TObj and TArg automatically from the method parameters:

void PersonMonitor::add(Person& p)
{
    using Poco::delegate;
    p.ENameChanged    += delegate(this, &PersonMonitor::onNameChanged);
    p.EAddressChanged += delegate(this, &PersonMonitor::onAddressChanged, 1000);
}

Having fixed that, I took another look at the method signature of the callback methods.
Prior the method signature was fixed to:

void method(const void* pSender, TArg& ref)

I hardly ever use the sender parameter but other’s might.
So the goal was to make

  • the sender parameter optional, i.e. accept method signature with/without sender
  • also allow to add static methods (e.g.: C functions)
  • be fully backwards compatible

Suffice to say, I succeeded. I won’t post the code here because it would be too much text.

Watch out for POCO 1.3.1 which will contain these extensions 🙂