对函数使用擦除-删除习惯用法<void(>
Using erase-remove idiom for function<void()>
叠人。
我试图实现一个观察者(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;
};
您的问题可以简化为两个std::function
实例无法比较是否相等。std::remove
需要operator==
,而std::function
没有。参见"为什么std::function不具有可比性?"
考虑以下情况:
假设你在main
中定义了两个lambda:
auto fn = [](){cout << "Hello.n"; };
auto fn2 = [](){cout << "Hello.n"; };
现在,这两个相等吗?他们做同样的事情,但也许这纯粹是巧合。如果第二个"Hello"
变成"Hello2"
,它们会变得不相等吗?如果第二个不再是lambda而是一个实函数void f()
,它们会不会不相等?
你有几个选项来解决手头的问题。一种是对指向std::function
对象的指针进行操作。指针可以比较,正确使用std::unique_ptr
可以确保正确处理释放。
或者为每个使用的std::function
分配一个标识符。请参阅以下修改后的代码示例,其中向量中直接存储的std::function<void()>
被替换为自定义类型EventFunction
,该类型将int
映射到函数对象。本例使用std::remove_if
只比较int
s:
#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);
};
尝试通过引用存储函数,但我不知道该怎么做那(或者如果可能的话)
这是不可能的,因为你不能在标准库容器中存储引用。但我想这个想法与我上面提到的指针类似。
相关文章:
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 在c++类上调用void函数
- 为什么野牛仍在使用"int yylex(void)",却找不到"int yylex(YYS
- 在派生函数中指定void*参数
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- C++为什么尽管我调用了void函数,它却不起作用
- 如何从void函数输出字符串
- 我应该使用什么来代替void作为变体中的替代类型之一
- 奇怪的结构&GCC&clang(void*返回类型)
- 呼叫运营商<<临时
- Arduino:for/while/if在void setup()或void loop()之前?——错误:之前需要不合格
- 为什么这个函数将"const char*"转换为"void* const"而不是"const void*"
- 引用一个已擦除类型(void*)的指针
- 将尾部调用void(i32,..)位转换为llvm::函数以获取FnAttribute
- 库函数需要一个 std::function<void(void)>,如何传入类函数?
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 如何将指针从一个void函数传递到另一个C++
- <<操作员在下面的行中工作
- 为什么我在使用void函数时得到错误代码C2276
- void*到驱动程序中的UnicodeString