Skip to content

Instantly share code, notes, and snippets.

@dsaltares
Last active August 29, 2015 14:00
Show Gist options
  • Save dsaltares/11212605 to your computer and use it in GitHub Desktop.
Save dsaltares/11212605 to your computer and use it in GitHub Desktop.
Utility class to handle a set of listeners and their callbacks using variadic templates
#ifndef __LISTENERSET_H__
#define __LISTENERSET_H__
#include <set>
/*
Usage:
class IInputListener
{
public:
virtual ~IInputListener() {}
virtual void keyDown(KeyCode code) = 0;
virtual void keyUp(KeyCode code) = 0;
};
...
ListenerSet<IInputListener*> listeners;
...
listeners.addListener(new PlayerInputListener());
listeners.addListener(new UserInterfaceInputListener());
...
listeners.notify(&IInputListener::keyDown, keyCode);
listeners.notify(&IInputListener::keyUp, keyCode);
*/
template <class Type> class ListenerSet
{
public:
ListenerSet() {}
virtual ~ListenerSet() {}
inline void addListener(Type listener)
{
if (m_notifying)
{
m_pendingAddition.insert(listener);
m_pendingRemoval.erase(listener);
}
else
{
m_listeners.insert(listener);
}
}
inline void removeListener(Type listener)
{
if (m_notifying)
{
m_pendingRemoval.insert(listener);
m_pendingAddition.erase(listener);
}
else
{
m_listeners.erase(listener);
}
}
template <class Function, class... Arguments>
inline void notify(Function&& f, Arguments&&... args)
{
m_notifying = true;
for (Type listener : m_listeners)
{
auto callback = std::bind(f, listener, args...);
callback(listener);
}
m_notifying = false;
for (Type listener : m_pendingRemoval)
{
m_listeners.erase(listener);
}
m_pendingRemoval.clear();
for (Type listener : m_pendingAddition)
{
m_listeners.insert(listener);
}
m_pendingAddition.clear();
}
private:
bool m_notifying;
std::set<Type> m_pendingRemoval;
std::set<Type> m_pendingAddition;
std::set<Type> m_listeners;
};
#endif // __LISTENERSET_H__
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment