I was trying to understand c++0x std::bind and std::function usage in event handling / callbacks. 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 ?:
template<typename Event, typename Listener>
bool bindEvent(const Listener& function)
Since in main method we call this function only with .
PS: Also, this code fails in std::is_convertible part. (as I understand, because of mismatch type from habindEvent<KeyboardEvent> (&do_key);
Listenerwill be inferred by the compiler to be the type of function pointer that you pass it, in this casevoid(const KeyboardEvent&).And your test fails because it’s the wrong way around: you want
instead (note the negation).
By the way, both
std::is_arrayandstd::is_convertableare decided at compile time, which means that you are using a run-time check for something that is statically determined. Instead, you can make the template fail to bind for invalid types using SFINAE:This will cause a compiler error if you try to instantiate the template with types that don’t match your conditions.