尝试使用 std::functional 和 std::bind 在 C++ 中创建 C# 样式的事件访问修饰符
Try to create C# style event access modifier in C++ using std::functional and std::bind
我正在尝试创建 C# 样式的事件处理,即为每个人公开 += 运算符并仅为包含 class.
公开 Invoke
方法
我正在使用 std::functional 和 std::bind 来创建回调机制:
C++ callback using class member
启用仅从包含 class 调用事件,
我创建了 Event::Invoke()
私有方法,然后我创建了 Event
的朋友 class,名为 ClassWithEvent
,它具有受保护的方法 InvokeEvent
,调用 Event::Invoke
。
ClassWithEvent
的所有继承 classes 都可以使用基础 class InvokeEvent
方法调用事件。
另外,我想让事件有不同类型的参数,所以我创建了基础 class EventArgs
可以由其他参数之王扩展。
#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);
}
};
例如,我有 ApplesTree
class 和 AppleFallEvent
事件,
我有 ApplesCollector
class 应该通知苹果掉落:
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;
}
好吧,我尝试编译它并得到以下错误:
C2672 'std::invoke': no matching overloaded function found
和
C2893 Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'
我看不出问题出在哪里,因为这个错误属于标准代码,很难处理。
无论如何,我发现如果我删除 Event::operator+=()
的用法,编译就会成功。
谁能指出这里的问题是什么?
谢谢!
这里的问题是您尝试绑定的事件处理程序方法与事件处理程序函数不匹配,因为 HandleAppleFallEvent
采用 const AppleFallEventArgs &
而不是 const EventArgs &
。
也有很多不必要的复制,比如for (function<void(const EventArgs &)> func : m_funcsList)
可以换成for (function<void(const EventArgs &)> & func : m_funcsList)
。
您需要 Event
知道它将使用哪些特定参数。请注意 using namespace std;
是个坏主意。我还用 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;
}
我正在尝试创建 C# 样式的事件处理,即为每个人公开 += 运算符并仅为包含 class.
公开Invoke
方法
我正在使用 std::functional 和 std::bind 来创建回调机制: C++ callback using class member
启用仅从包含 class 调用事件,
我创建了 Event::Invoke()
私有方法,然后我创建了 Event
的朋友 class,名为 ClassWithEvent
,它具有受保护的方法 InvokeEvent
,调用 Event::Invoke
。
ClassWithEvent
的所有继承 classes 都可以使用基础 class InvokeEvent
方法调用事件。
另外,我想让事件有不同类型的参数,所以我创建了基础 class EventArgs
可以由其他参数之王扩展。
#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);
}
};
例如,我有 ApplesTree
class 和 AppleFallEvent
事件,
我有 ApplesCollector
class 应该通知苹果掉落:
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;
}
好吧,我尝试编译它并得到以下错误:
C2672 'std::invoke': no matching overloaded function found
和
C2893 Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'
我看不出问题出在哪里,因为这个错误属于标准代码,很难处理。
无论如何,我发现如果我删除 Event::operator+=()
的用法,编译就会成功。
谁能指出这里的问题是什么?
谢谢!
这里的问题是您尝试绑定的事件处理程序方法与事件处理程序函数不匹配,因为 HandleAppleFallEvent
采用 const AppleFallEventArgs &
而不是 const EventArgs &
。
也有很多不必要的复制,比如for (function<void(const EventArgs &)> func : m_funcsList)
可以换成for (function<void(const EventArgs &)> & func : m_funcsList)
。
您需要 Event
知道它将使用哪些特定参数。请注意 using namespace std;
是个坏主意。我还用 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;
}