堆积的人。
我试图为我的程序实现一个观察者(esque?)模式。我有一个组件,用于存储事件发生时应调用的函数。我的问题是,如果需要,我不知道如何从容器中删除我的功能。尝试通过引用存储函数,但我不知道该怎么做(或者如果可能的话。)
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
enum class EVENT_TYPE{
anEvent
};
class EventableComponent{
map<EVENT_TYPE, vector<function<void()>>> listeners;
public:
void trigger(EVENT_TYPE _et){
for(auto& it : listeners[_et]){
it();
}
}
void registerListener(EVENT_TYPE _et, function<void()> _fn){
listeners[_et].push_back(_fn);
};
void removeListener(EVENT_TYPE _et, function<void()> _fn){
//error C2678: binary '==' : no operator found which takes a left-hand operand of type 'std::function<void (void)>'
//(or there is no acceptable conversion)
listeners[_et].erase(remove(listeners[_et].begin(), listeners[_et].end(), _fn), listeners[_et].end());
};
};
int main(){
EventableComponent ec;
// this would become a member function for a class somewhere down the line
auto fn = [](){cout << "Hello.\n"; };
ec.registerListener(EVENT_TYPE::anEvent, fn);
ec.trigger(EVENT_TYPE::anEvent);
ec.removeListener(EVENT_TYPE::anEvent, fn);
ec.trigger(EVENT_TYPE::anEvent);
cin.get();
return 0;
};
答案 0 :(得分:3)
您的问题可以简化为无法比较两个std::function
实例的相等性。 std::remove
需要operator==
,std::function
没有main
。请参阅"Why is std::function not equality comparable?"。
考虑以下情况。
假设您在auto fn = [](){cout << "Hello.\n"; };
auto fn2 = [](){cout << "Hello.\n"; };
中定义了两个lambdas:
"Hello"
现在,这两个是否平等?他们做同样的事情,但也许这纯属巧合。如果第二个"Hello2"
成为void f()
,它们会变得不平等吗?如果第二个不再是lambda而是真正的函数std::function
,它们会变得不平等吗?
事实是,对于函数对象,没有通常有用的相等定义,因此您可以在 的上下文中定义相等的真正含义程序
您有几种方法可以解决手头的问题。一种方法是对指针操作std::unique_ptr
个对象。可以比较指针,正确使用std::function
可以确保正确处理解除分配。
或者为您使用的每个std::function<void()>
分配一个标识符。请参阅以下代码修改示例,其中向量中的EventFunction
直接存储将替换为将int
映射到函数对象的自定义类型std::remove_if
。该示例使用int
仅比较#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
enum class EVENT_TYPE{
anEvent
};
struct EventFunction {
function<void()> f;
int id;
};
class EventableComponent{
map<EVENT_TYPE, vector<EventFunction>> listeners;
public:
void trigger(EVENT_TYPE _et){
for(auto& it : listeners[_et]){
it.f();
}
}
void registerListener(EVENT_TYPE _et, EventFunction _fn){
listeners[_et].push_back(_fn);
};
void removeListener(EVENT_TYPE _et, int function_id){
//error C2678: binary '==' : no operator found which takes a left-hand operand of type 'std::function<void (void)>'
//(or there is no acceptable conversion)
listeners[_et].erase(remove_if(listeners[_et].begin(), listeners[_et].end(),
[&](EventFunction const& e) { return e.id == function_id; }), listeners[_et].end());
};
};
int main(){
EventableComponent ec;
// this would become a member function for a class somewhere down the line
auto fn = [](){cout << "Hello.\n"; };
ec.registerListener(EVENT_TYPE::anEvent, EventFunction{ fn, 1 });
ec.trigger(EVENT_TYPE::anEvent);
ec.removeListener(EVENT_TYPE::anEvent, 1);
ec.trigger(EVENT_TYPE::anEvent);
};
s:
UIBarButtonItem
尝试通过引用存储函数,但我不知道该怎么做 那(或者如果可能的话。)
这是不可能的,因为您无法在标准库容器中存储引用。但我想这个想法类似于我上面提到的指针。