[英]Try to create C# style event access modifier in C++ using std::functional and std::bind
我正在嘗試創建 C# 樣式的事件處理,即為所有人公開 += 運算符,並僅為包含類公開Invoke
方法。
我正在使用 std::functional 和 std::bind 來創建回調機制: C++ callback using class member
為了僅從包含類調用事件,我創建了Event::Invoke()
方法私有,然后我創建了一個名為ClassWithEvent
的Event
朋友類,它具有調用Event::Invoke
保護方法InvokeEvent
。 ClassWithEvent
所有繼承類ClassWithEvent
可以使用基類InvokeEvent
方法調用事件。
此外,我想讓事件具有不同類型的 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);
}
};
對於的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;
}
好吧,我嘗試編譯它並收到以下錯誤:
C2672“std::invoke”:找不到匹配的重載函數
和
C2893 未能專門化函數模板“未知類型 std::invoke(_Callable &&,_Types &&...)”
我看不出問題出在哪里,因為這個錯誤屬於標准代碼,很難處理。 無論如何,我發現如果我刪除Event::operator+=()
的使用,則編譯成功。
有人可以指出這里的問題是什么嗎?
謝謝!
您需要讓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;
}
這里的問題是您嘗試綁定的事件處理程序方法與事件處理程序函數不匹配,因為HandleAppleFallEvent
采用const AppleFallEventArgs &
而不是const EventArgs &
。
還有很多不必要的復制,例如for (function<void(const EventArgs &)> func : m_funcsList)
可以替換for (function<void(const EventArgs &)> & func : m_funcsList)
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.