Skip to content

Instantly share code, notes, and snippets.

@redrabbit
Last active June 29, 2017 22:44
Show Gist options
  • Save redrabbit/1958871 to your computer and use it in GitHub Desktop.
Save redrabbit/1958871 to your computer and use it in GitHub Desktop.
Generic C++ notification dispatcher with boost::signal2
#include <map>
#include <queue>
#include <typeinfo>
#include <iostream>
#include <boost/signals2/signal.hpp>
#include <boost/type_traits/is_base_of.hpp>
class notification_interface
{
public:
virtual void trigger( boost::signals2::signal_base* ) = 0;
};
template< typename signature_t >
class abstract_notification : public notification_interface
{
public:
typedef signature_t callback;
protected:
virtual void notify( boost::signals2::signal< callback >& signal ) = 0;
private:
void trigger( boost::signals2::signal_base* base_signal )
{
typedef boost::signals2::signal< signature_t > signal_t;
signal_t* signal = dynamic_cast< signal_t* >( base_signal );
if( !signal )
{
throw; // bad dynamic cast
}
notify( *signal );
}
};
class foo_notification : public abstract_notification< void ( int ) >
{
public:
foo_notification( int foo ) : m_foo( foo ) { }
protected:
virtual void notify( boost::signals2::signal< callback >& signal )
{
signal( m_foo );
}
private:
int m_foo;
};
class bar_notification : public foo_notification
{
public:
bar_notification( ) : foo_notification( 0 ) { }
protected:
virtual void notify( boost::signals2::signal< callback >& signal )
{
signal( 12 );
}
};
class notification_manager
{
public:
virtual ~notification_manager( )
{
// delete registered signals
}
template< typename notification_t >
boost::signals2::connection register_callback( const boost::function< typename notification_t::callback >& callback )
{
if( !boost::is_base_of< notification_interface, notification_t >::value )
{
throw; // template parameter is not a notification type
}
typedef boost::signals2::signal< typename notification_t::callback > signal_t;
const std::string type_name = typeid( notification_t ).name( );
signal_t* signal = 0;
if( m_signals.find( type_name ) != m_signals.end( ) )
{
signal = dynamic_cast< signal_t* >( m_signals[ type_name ] );
}
else
{
signal = new signal_t( );
m_signals[ type_name ] = signal;
}
return signal->connect( callback );
}
void dispatch( notification_interface* notification )
{
m_queue.push( notification );
}
void poll( )
{
while( !m_queue.empty( ) )
{
notification_interface* notification = m_queue.front( );
std::map< std::string, boost::signals2::signal_base* >::const_iterator iter;
iter = m_signals.find( typeid( *notification ).name( ) );
if( iter != m_signals.end( ) )
{
notification->trigger( iter->second );
}
m_queue.pop( );
delete notification;
}
}
private:
std::map< std::string, boost::signals2::signal_base* > m_signals;
std::queue< notification_interface* > m_queue;
};
void foo_callback( int foo )
{
std::cout << "foo: " << foo << std::endl;
}
void bar_callback( int bar )
{
std::cout << "bar: " << bar << std::endl;
}
int main( )
{
notification_manager man;
man.register_callback< bar_notification >( bar_callback );
man.register_callback< foo_notification >( foo_callback );
man.dispatch( new bar_notification );
man.dispatch( new bar_notification );
man.dispatch( new foo_notification( 42 ) );
man.poll( );
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment