[英]std::bind and std::function usage in callbacks
I was trying to understand c++0x std::bind and std::function usage in event handling / callbacks.我试图了解 c++0x std::bind 和 std::function 在事件处理/回调中的用法。 So I was examining some code snippets and encountered some interesting places which I can't fully understand.所以我在检查一些代码片段,遇到了一些我无法完全理解的有趣的地方。
Let's say we have:假设我们有:
class EventHandler
{
public:
template<typename Event, typename Listener>
bool bindEvent (const Listener& function)
{
if (std::is_array<Event>::value)
{
std::cout << "You cannot register an array as an event type" << std::endl;
return false;
}
if (std::is_convertible<Listener, std::function<void (Event&)>>::value)
{
std::cout << "Invalid callback for this event type" << std::endl;
return false;
}
listeners.insert(std::make_pair(&typeid(typename std::decay<Event>::type),
[=](void* ev) { function(*static_cast<Event*>(ev)); }));
}
private:
// for each event type, we have a list of callbacks
// these callbacks are of the form std::function<void (void*)>
// because we will convert between the &event and void*
typedef std::function <void (void*)> fun;
std::unordered_multimap <const std::type_info*, fun> listeners;
};
// example of an event type
struct KeyboardEvent
{
int keyCode;
};
// example of an event callback
void do_key (const KeyboardEvent &event)
{
std::cout << "I am working" << std::endl;
}
int main (int argc, char** argv)
{
EventHandler handler;
handler.bindEvent<KeyboardEvent> (&do_key); // fixed typo
return 0;
}
Question: What type does Listener holds in this part?:问题: Listener在这部分中持有什么类型?:
template<typename Event, typename Listener>
bool bindEvent(const Listener& function)
Since in main method we call this function only with.由于在 main 方法中,我们仅将其称为 function。
PS: Also, this code fails in std::is_convertible part. PS:此外,此代码在 std::is_convertible 部分失败。 (as I understand, because of mismatch type from habindEvent<KeyboardEvent> (&do_key);
(据我了解,由于habindEvent<KeyboardEvent> (&do_key);
Listener
will be inferred by the compiler to be the type of function pointer that you pass it, in this case void(const KeyboardEvent&)
. Listener
将被编译器推断为您传递给它的 function 指针的类型,在本例中为void(const KeyboardEvent&)
。
And your test fails because it's the wrong way around: you want你的测试失败了,因为这是错误的方法:你想要
if (!std::is_convertible<Listener, std::function<void (Event&)>>::value)
instead (note the negation).相反(注意否定)。
By the way, both std::is_array
and std::is_convertable
are decided at compile time, which means that you are using a run-time check for something that is statically determined.顺便说一句, std::is_array
和std::is_convertable
都是在编译时决定的,这意味着您正在对静态确定的东西使用运行时检查。 Instead, you can make the template fail to bind for invalid types using SFINAE:相反,您可以使用 SFINAE 使模板无法绑定无效类型:
template<typename Event, typename Listener>
typename std::enable_if<!std::is_array<Event>::value && std::is_convertible<Listener, std::function<void(Event&)>>::value, bool>::type bindEvent (const Listener& function)
{
}
This will cause a compiler error if you try to instantiate the template with types that don't match your conditions.如果您尝试使用与您的条件不匹配的类型来实例化模板,这将导致编译器错误。
Well first I assume that habindEvent<KeyboardEvent> (&do_key);
首先我假设habindEvent<KeyboardEvent> (&do_key);
is a typo and should be handler.bindEvent<KeyboardEvent>(&do_key)
.是一个错字,应该是handler.bindEvent<KeyboardEvent>(&do_key)
。
So the type of the listener is a template deduction from the parameter.所以监听器的类型是从参数中推导出来的模板。 So in your special case it would be this.所以在你的特殊情况下就是这样。
typedef void(*Fn_t)(const KeyboardEvent &);
EventHandler handler;
handler.bindEvent<KeyboardEvent, Fn_t> (&do_key);
But you don't need the Fn_t since the compiler can do this work for you.但是您不需要 Fn_t,因为编译器可以为您完成这项工作。
And after fixing your type the code compiles on my machine.在修正你的类型之后,代码会在我的机器上编译。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.