I'm trying to create C# style event handling, i.e expose += operator for everybody and expose Invoke
method only for the containing class.
I'm using std::functional and std::bind as explained here to create callback mechanism: C++ callback using class member
To enable invoking the event only from containing class,
I created Event::Invoke()
method private, and then I create a friend class of Event
called ClassWithEvent
thats has protected method InvokeEvent
which calling Event::Invoke
.
All the inheritanced classes of ClassWithEvent
can invoke the event using base class InvokeEvent
method.
Additionly, I want to enable events to have different kind of args, so I create base class EventArgs
which can be extended by other king of args.
#include <iostream>
#include <vector>
#include <functional>
using namespace std;
using namespace placeholders;
class EventArgs
{
};
class Event
{
friend class ClassWithEvent;
public:
void operator+=(function<void(const EventArgs &)> callback)
{
m_funcsList.push_back(callback);
}
protected:
void Invoke(const EventArgs & args) const
{
for (function<void(const EventArgs &)> func : m_funcsList)
{
func(args);
}
}
vector<function<void(const EventArgs &)>> m_funcsList;
};
class ClassWithEvent
{
protected:
void InvokeEvent(const Event & event, const EventArgs & args)
{
event.Invoke(args);
}
};
For exaple, I have ApplesTree
class with AppleFallEvent
event,
I have ApplesCollector
class which should be notified about falling apples:
class AppleFallEventArgs : public EventArgs
{
public:
int size;
int weight;
};
class ApplesTree : public ClassWithEvent
{
public:
Event AppleFallEvent;
void triggerAppleFall(int size, int weight)
{
AppleFallEventArgs args;
args.size = size;
args.weight = weight;
ClassWithEvent::InvokeEvent(AppleFallEvent, args);
}
};
class ApplesCollector
{
public:
void HandleAppleFallEvent(const AppleFallEventArgs & args)
{
cout << "Apple size is " << args.size << "weight is " << args.weight << endl;
}
};
int main(int argc, char* argv[])
{
ApplesTree applesTree;
ApplesCollector applesCollector;
applesTree.AppleFallEvent += bind(&ApplesCollector::HandleAppleFallEvent, &applesCollector, _1);
applesTree.triggerAppleFall(1, 2);
return 0;
}
Well, I try to compile this and get the following errors:
C2672 'std::invoke': no matching overloaded function found
and
C2893 Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'
I can't look out where is the problem because this errors belongs to std code and its really hard to deal with it.
Any way, I found that if I removing the usage of Event::operator+=()
the compile is successfull.
Can someone point out what is the problem here?
Thanks!