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 overlo
You absolutely can. James McNellis has already linked to a complete solution, but for your toy example we can do the following:
#include
using namespace std;
typedef int(*MyFunc)(float);
template
class MyEvent;
template
class MyEvent
{
typedef R (*FuncType)(Arg);
deque ls;
public:
MyEvent& operator+=(FuncType t)
{
ls.push_back(t);
return *this;
}
void operator()(Arg arg)
{
typename deque::iterator i = ls.begin();
typename deque::iterator e = ls.end();
for(; i != e; ++i) {
(*i)(arg);
}
}
};
static int test(float f){return (int)f; }
int main(){
MyEvent e;
e += test;
e(2.0);
}
Here I've made use of partial specialization to tease apart the components of the function pointer type to discover the argument type. boost.signals does this and more, leveraging features such as type erasure, and traits to determine this information for non-function pointer typed callable objects.
For N arguments there are two approaches. The "easy' way, that was added for C++0x, is leveraging variadic templates and a few other features. However, we've been doing this since before that features was added, and I don't know which compilers if any, support variadic templates yet. So we can do it the hard way, which is, specialize again:
template
class MyEvent
{
typedef R (*FuncType)(Arg0, Arg1);
deque ls;
...
void operatror()(Arg0 a, Arg1)
{ ... }
MyEvent& operator+=(FuncType f)
{ ls.push_back(f); }
...
};
THis gets tedious of course which is why have libraries like boost.signals that have already banged it out (and those use macros, etc. to relieve some of the tedium).
To allow for a MyEvent
style syntax you can use a technique like the following
struct NullEvent;
template
class HisEvent;
template<>
struct HisEvent
{ void operator()() {} };
template
struct HisEvent
{ void operator()(A a) {} };
template
struct HisEvent
{
void operator()(A a, B b) {}
};
template
struct HisEvent
{
void operator()(A a, B b, C c)
{}
};
static int test(float f){return (int)f; }
int main(){
MyEvent e;
e += test;
e(2.0);
HisEvent h;
HisEvent h2;
}
The NullEvent
type is used as a placeholder and we again use partial specialization to figure out the arity.