I wanted to implement a C# event in C++ just to see if I could do it. I got stuck, I know the bottom is wrong but what I realize my biggest problem is…
How do I overload the () operator to be whatever is in T, in this case int func(float)? I can’t? Can I? Can I implement a good alternative?
#include <deque>
using namespace std;
typedef int(*MyFunc)(float);
template<class T>
class MyEvent
{
deque<T> ls;
public:
MyEvent& operator +=(T t)
{
ls.push_back(t);
return *this;
}
};
static int test(float f){return (int)f; }
int main(){
MyEvent<MyFunc> e;
e += test;
}
If you can use Boost, consider using Boost.Signals2, which provides signals-slots/events/observers functionality. It’s straightforward and easy to use and is quite flexible. Boost.Signals2 also allows you to register arbitrary callable objects (like functors or bound member functions), so it’s more flexible, and it has a lot of functionality to help you manage object lifetimes correctly.
If you are trying to implement it yourself, you are on the right track. You have a problem, though: what, exactly, do you want to do with the values returned from each of the registered functions? You can only return one value from
operator(), so you have to decide whether you want to return nothing, or one of the results, or somehow aggregate the results.Assuming we want to ignore the results, it’s quite straightforward to implement this, but it’s a bit easier if you take each of the parameter types as a separate template type parameter (alternatively, you could use something like Boost.TypeTraits, which allows you to easily dissect a function type):
This requires the registered function to have a
voidreturn type. To be able to accept functions with any return type, you can changeFuncPtrto be(or use
boost::functionorstd::tr1::functionif you don’t have the C++0x version available). If you do want to do something with the return values, you can take the return type as another template parameter toMyEvent. That should be relatively straightforward to do.With the above implementation, the following should work:
Another approach, which allows you to support different arities of events, would be to use a single type parameter for the function type and have several overloaded
operator()overloads, each taking a different number of arguments. These overloads have to be templates, otherwise you’ll get compilation errors for any overload not matching the actual arity of the event. Here’s a workable example:(I’ve used
std::add_pointerfrom C++0x here, but this type modifier can also be found in Boost and C++ TR1; it just makes it a little cleaner to use the function template since you can use a function type directly; you don’t have to use a function pointer type.) Here’s a usage example: