有没有办法为函数和成员函数使用函数指针?
我想创建一种事件句柄,它可以保存类的成员函数,同时它应该能够拥有“普通”函数指针。
编辑:我找到了解决方案。可能不是最好的一个而是一个;Event.h
#include <map>
class BasicEvent {
public:
BasicEvent(int id) : eventId(id)
{}
int GetId() const
{
return eventId;
}
virtual void ObjectMethode() {}
protected:
const int eventId;
};
class BasicEventHandler {
public:
void Trigger(BasicEvent* event)
{
if (this->eventMap.find(event->GetId()) != this->eventMap.end()) {
eventMap[event->GetId()](event);
}
}
void AddEvent(int id, std::function<int(BasicEvent*)> eventFunction)
{
eventMap[id] = eventFunction;
}
void RemoveEvent(int id)
{
this->eventMap.erase(id);
}
private:
std::map<int, std::function<int(BasicEvent*)>> eventMap;
};
的main.cpp
class CustomEvent : public BasicEvent {
public:
CustomEvent(int id) : tq::BasicEvent(id)
{
x = 9;
y = 8;
}
struct {
int x;
int y;
};
void ObjectMethode()
{
std::cout << this->eventId << " Custom Event: X: " << x << " Y: " << y << '\n';
}
};
int main() {
BasicEventHandler myHandler;
myHandler.AddEvent(0, [&](BasicEvent* event) {
std::cout << " EVENT <" << event->GetId() << "> Triggered!\n";
return 0;
});
myHandler.AddEvent(1, [&](tq::BasicEvent* event) {
event->ObjectMethode();
return 0;
});
myHandler.Trigger(&BasicEvent(0));
myHandler.Trigger(&CustomEvent(1));
return 0;
}
答案 0 :(得分:2)
C ++ 11和Lambdas .. yay !!
所以我们走了......
让我们有一个函数,你的事件处理程序将采用谓词(一个返回true或false的函数)和两个函数,即on_sucess
和on_error
。
如果test_predicate
返回true
,则应调用on_success
,否则将调用on_error
。
template<typename Predicate, typename OnSucess, typename OnError>
void single_event_handler (Predicate && test_predicate,
OnSucess && on_success,
OnError && on_error)
{
if( test_predicate() )
on_success();
else
on_error();
}
现在是我们的来电方。 在这里,我们有3个函数可以放入这个模式中。
bool is_even(int num) { return !(num % 2); }
void on_even_found() { std::cout << "Number passed is even\n"; }
void on_odd_found() { std::cout << "Number passed is odd\n"; };
但正如您所看到的,is_even
函数不适合test_predicate
的签名。 is_even(int)
只接受一个参数,而test_predicate()
则不接受任何参数。
那我们该如何解决这个问题?
我们将它包装成另外一个函数和/或lambda,然后传递它。
指导原则:可以通过再添加一层来解决每个问题。
// wrap it in another function or lambda
auto is_5_even = []() { return is_even(5); };
auto is_4_even = []() { return is_even(4); };
现在,一旦我们的所有拼图准备就绪,我们就会创建自己的事件处理程序。
// caller side - pair the final structure
single_event_handler(is_5_even, on_even_found, on_odd_found);
single_event_handler(is_4_even, on_even_found, on_odd_found);
现在,通过使用绑定和函数指针,可以在预C ++ 11中实现此代码。
遗憾的是,std::bind
和std::function
是在C ++ 11中引入的,您必须使用其他替代方案,例如boost库。
此外,另一个包装器可以写在single_event_handler
之上,它可以同时管理多个事件,但我认为我们必须创建另一个函数register_event
,以便它可以有效地使用。 / p>
以下是完整的工作代码,供您参考(使用g++ -std=c++11
编译)
#include <iostream>
template<typename Predicate, typename OnSucess, typename OnError>
void single_event_handler (Predicate && test_predicate,
OnSucess && on_success,
OnError && on_error)
{
if( test_predicate() )
on_success();
else
on_error();
}
bool is_even(int num) { return !(num % 2); }
void on_even_found() { std::cout << "Number passed is even\n"; }
void on_odd_found() { std::cout << "Number passed is odd\n"; };
int main()
{
// caller side
auto is_5_even = []() { return is_even(5); };
auto is_4_even = []() { return is_even(4); };
single_event_handler(is_5_even, on_even_found, on_odd_found);
single_event_handler(is_4_even, on_even_found, on_odd_found);
return 0;
}
答案 1 :(得分:1)
接受您的处理程序作为std::function
,然后客户端可以传入他们想要的任何内容。无论是功能,lambdas,其他仿函数,你都可以命名。
模板将为您处理细节,客户可以选择他们希望如何调用。
答案 2 :(得分:1)
成员函数在哪里获得“this”指针? 这两个函数不能具有相同的签名。 也许,你最好的选择是创建一个lambda,它将捕获“this”,并将其发送给你的事件处理程序。
std::function
将能够为您保留。