[英]Try to create C# style event access modifier in C++ using std::functional and std::bind
I'm trying to create C# style event handling, ie expose += operator for everybody and expose Invoke
method only for the containing class.我正在尝试创建 C# 样式的事件处理,即为所有人公开 += 运算符,并仅为包含类公开Invoke
方法。
I'm using std::functional and std::bind as explained here to create callback mechanism: C++ callback using class member我正在使用 std::functional 和 std::bind 来创建回调机制: 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
.为了仅从包含类调用事件,我创建了Event::Invoke()
方法私有,然后我创建了一个名为ClassWithEvent
的Event
朋友类,它具有调用Event::Invoke
保护方法InvokeEvent
。 All the inheritanced classes of ClassWithEvent
can invoke the event using base class InvokeEvent
method. ClassWithEvent
所有继承类ClassWithEvent
可以使用基类InvokeEvent
方法调用事件。
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.此外,我想让事件具有不同类型的 args,所以我创建了基类EventArgs
,它可以被其他 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:对于的exaple,我有ApplesTree
带班AppleFallEvent
事件,我有ApplesCollector
应当通知有关掉落的苹果类:
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 C2672“std::invoke”:找不到匹配的重载函数
and和
C2893 Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)' C2893 未能专门化函数模板“未知类型 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.无论如何,我发现如果我删除Event::operator+=()
的使用,则编译成功。
Can someone point out what is the problem here?有人可以指出这里的问题是什么吗?
Thanks!谢谢!
You need to have Event
know which particular args it will use.您需要让Event
知道它将使用哪些特定的参数。 Note that using namespace std;
注意using namespace std;
is a bad idea.是个坏主意。 I've also replaced the bind
with a lambda.我还用 lambda 替换了bind
。
// no empty class EventArgs
template<typename EventArgs>
class Event
{
friend class ClassWithEvent;
public:
void operator+=(std::function<void(const EventArgs &)> callback)
{
m_funcsList.emplace_back(std::move(callback));
}
private:
void Invoke(const EventArgs & args) const
{
for (auto & func : m_funcsList)
{
func(args);
}
}
std::vector<std::function<void(const EventArgs &)>> m_funcsList;
};
class ClassWithEvent
{
protected:
template<typename EventArgs>
void InvokeEvent(const Event<EventArgs> & event, const EventArgs & args)
{
event.Invoke(args);
}
};
class AppleFallEventArgs
{
public:
int size;
int weight;
};
class ApplesTree : public ClassWithEvent
{
public:
Event<AppleFallEventArgs> AppleFallEvent;
void triggerAppleFall(int size, int weight)
{
AppleFallEventArgs args;
args.size = size;
args.weight = weight;
InvokeEvent(AppleFallEvent, args);
}
};
class ApplesCollector
{
public:
void HandleAppleFallEvent(const AppleFallEventArgs & args)
{
std::cout << "Apple size is " << args.size << "weight is " << args.weight << std::endl;
}
};
int main(int argc, char* argv[])
{
ApplesTree applesTree;
ApplesCollector applesCollector;
applesTree.AppleFallEvent += [&](auto & args){ applesCollector.HandleAppleFallEvent(args); };
applesTree.triggerAppleFall(1, 2);
return 0;
}
The problem here is that event handler method that you are trying to bind does not match event handler function because HandleAppleFallEvent
takes const AppleFallEventArgs &
instead of const EventArgs &
.这里的问题是您尝试绑定的事件处理程序方法与事件处理程序函数不匹配,因为HandleAppleFallEvent
采用const AppleFallEventArgs &
而不是const EventArgs &
。
Also there are a lot of unnecessary copying, for example for (function<void(const EventArgs &)> func : m_funcsList)
can be replaced with for (function<void(const EventArgs &)> & func : m_funcsList)
.还有很多不必要的复制,例如for (function<void(const EventArgs &)> func : m_funcsList)
可以替换for (function<void(const EventArgs &)> & func : m_funcsList)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.