对函数使用擦除-删除习语<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
没有。参见 "Why is std::function not equality comparable?"。
考虑以下情况。
假设您在 main
:
中定义了两个 lambda
auto fn = [](){cout << "Hello.\n"; };
auto fn2 = [](){cout << "Hello.\n"; };
现在,这两个是否相等?他们做同样的事情,但这也许纯属巧合。如果第二个 "Hello"
变成 "Hello2"
,它们会变得不相等吗?如果第二个不再是 lambda 而是一个实函数,它们会变得不相等吗 void f()
?
问题是函数对象没有通常有用的相等性定义,所以由您来定义相等性在[=46的上下文中的真正含义=]你的程序。
您有多种选择来解决手头的问题。一种是对 指针 到 std::function
对象进行操作。可以比较指针,正确使用 std::unique_ptr
可确保正确处理释放。
或者您为每个使用的 std::function
分配一个标识符。请参阅以下修改后的代码示例,其中向量中 std::function<void()>
的直接存储被替换为将 int
映射到函数对象的自定义类型 EventFunction
。该示例使用 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);
};
Tried storing the functions by reference, but iam not sure how to do
that(or if thats possible.)
这是不可能的,因为您不能在标准库容器中存储引用。但我想这个想法与我上面提到的带有指针的想法类似。
人山人海。
我正在尝试为我的程序实现一个观察者(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
没有。参见 "Why is std::function not equality comparable?"。
考虑以下情况。
假设您在 main
:
auto fn = [](){cout << "Hello.\n"; };
auto fn2 = [](){cout << "Hello.\n"; };
现在,这两个是否相等?他们做同样的事情,但这也许纯属巧合。如果第二个 "Hello"
变成 "Hello2"
,它们会变得不相等吗?如果第二个不再是 lambda 而是一个实函数,它们会变得不相等吗 void f()
?
问题是函数对象没有通常有用的相等性定义,所以由您来定义相等性在[=46的上下文中的真正含义=]你的程序。
您有多种选择来解决手头的问题。一种是对 指针 到 std::function
对象进行操作。可以比较指针,正确使用 std::unique_ptr
可确保正确处理释放。
或者您为每个使用的 std::function
分配一个标识符。请参阅以下修改后的代码示例,其中向量中 std::function<void()>
的直接存储被替换为将 int
映射到函数对象的自定义类型 EventFunction
。该示例使用 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);
};
Tried storing the functions by reference, but iam not sure how to do that(or if thats possible.)
这是不可能的,因为您不能在标准库容器中存储引用。但我想这个想法与我上面提到的带有指针的想法类似。