Note: This makes use of auto keyword and variadic templates, both of which are available in compilers with full or moderate C++0x support. I also have a FOREACH macro, which is not supplied. It simply iterates through a container.
Delegate.hpp
[source lang="cpp"]
#include "detail/Delegate.hpp"
template <typename Signature>
class Delegate
{};
template <typename R, typename... P>
class Delegate<R(P...)>
{
public:
Delegate(R(*FuncPtr)(P...))
{
new (&base) detail::FunctionDelegate<R(P...)>(FuncPtr);
}
template <typename Object>
Delegate(Object &object, R(Object::*MemPtr)(P...))
{
new (&base) detail::ObjectDelegate<Object, R(P...)>(&object, MemPtr);
}
R operator()(P... values)
{
return reinterpret_cast<detail::BaseDelegate<R(P...)>*>(&base)->Invoke(values...);
}
bool operator==(const Delegate<R(P...)> &rhs)
{
return reinterpret_cast<detail::BaseDelegate<R(P...)>*>(&base)->Equals(reinterpret_cast<const detail::BaseDelegate<R(P...)>*>(&rhs.base));
}
private:
char base[sizeof( detail::ObjectDelegate<class GenericClass, void()> )];
};
[/source]
detail/Delegate.hpp
[source lang="cpp"]
template <typename Signature>
class BaseDelegate
{};
template <typename Signature>
class FunctionDelegate : public BaseDelegate<Signature>
{};
template <typename Object, typename Signature>
class ObjectDelegate : public BaseDelegate<Signature>
{};
template <typename R, typename... P>
class BaseDelegate<R(P...)>
{
public:
virtual R Invoke(P... values) = 0;
virtual bool Equals(const BaseDelegate<R(P...)>* rhs) = 0;
};
template <typename R, typename... P>
class FunctionDelegate<R(P...)> : public BaseDelegate<R(P...)>
{
public:
typedef R(*CallbackType)(P...);
FunctionDelegate(CallbackType ptr)
: mptr(ptr)
{}
R Invoke(P... values)
{
return mptr(values...);
}
bool Equals(const BaseDelegate<R(P...)>* rhs)
{
auto p_rhs = static_cast<const FunctionDelegate<R(P...)>*>(rhs);
return (mptr == p_rhs->mptr);
}
private:
CallbackType mptr;
};
template <typename Object, typename R, typename... P>
class ObjectDelegate<Object, R(P...)> : public BaseDelegate<R(P...)>
{
public:
typedef R(Object::*CallbackType)(P...);
ObjectDelegate(Object *object, CallbackType MemPtr)
: mObjectPtr(object), mMemPtr(MemPtr)
{}
R Invoke(P... values)
{
return (mObjectPtr->*mMemPtr)(values...);
}
bool Equals(const BaseDelegate<R(P...)>* rhs)
{
auto p_rhs = static_cast<const ObjectDelegate<Object, R(P...)>*>(rhs);
return (mObjectPtr == p_rhs->mObjectPtr) && (mMemPtr == p_rhs->mMemPtr);
}
private:
Object *mObjectPtr;
CallbackType mMemPtr;
};
[/source]
Event.hpp
[source lang="cpp"]
template <typename Signature>
class Event
{};
template <typename R, typename... P>
class Event<R(P...)>
{
public:
typedef Delegate<R(P...)> CallbackType;
Event() {}
void Add(CallbackType func)
{
Callbacks.push_back(func);
}
template <typename Object>
void Add(Object &obj, R(Object::*MemPtr)(P...))
{
Callbacks.push_back(CallbackType(obj, MemPtr));
}
void Remove(CallbackType func)
{
Callbacks.erase(std::remove(Callbacks.begin(), Callbacks.end(), func));
}
template <typename Object>
void Remove(Object &obj, R(Object::*MemPtr)(P...))
{
Callbacks.erase(std::remove(Callbacks.begin(), Callbacks.end(), CallbackType(obj, MemPtr)));
}
R operator()(P... values)
{
FOREACH(Callback, Callbacks)
{
(*Callback)(values...);
}
}
private:
std::list<CallbackType> Callbacks;
};
[/source]
Example usage (similar to boost)
Event<void()> myEvent;
myEvent.Add(&SomeFunction);
myEvent.Add(someObject, &SomeObject::MemberFunction);
myEvent();
My initial testing of this has been with GCC 4.5.1. With default optimization, my Event class was 18x faster than a Boost.Signal, only testing for invocation speed. With -O2 optimization, it was about 10x faster.
What do you think? Any suggestions?