#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mpl = boost::mpl; namespace lambda = boost::lambda; template class Notifier { struct notifier_combiner { typedef boost::optional< int > result_type; template result_type operator()(INPUT_ITERATOR pFirst, INPUT_ITERATOR pLast) const { result_type res; for (; pFirst != pLast; ++pFirst) res = *pFirst; return res; } }; template struct get_member_type { typedef typename mpl::at< ID_TO_MEMBER_MAP_TYPE , INTEGRALC >::type type; }; template struct get_signal_type { typedef boost::signal< int (OBJECT_TYPE const*, typename get_member_type< INTEGRALC >::type) , notifier_combiner > type; }; template struct signal_holder { typename get_signal_type< INTEGRALC >::type sig; }; // generate inheritance hierachy to hold instances of all ids' // signal types typedef typename mpl::inherit_linearly< ID_TO_MEMBER_MAP_TYPE , mpl::inherit< mpl::_1 , signal_holder< mpl::first< mpl::_2 > > > >::type signals_t; // helper to easily retrieve a signal from the member id template inline typename get_signal_type< INTEGRALC >::type &get_signal(signal_holder< INTEGRALC > &s) { std::cout << "Notifier::get_signal_type<" << INTEGRALC::type::value << ">" << std::endl; return s.sig; } signals_t m_signals; public: Notifier() : m_signals() { std::cout << "Notifier::Notifier" << std::endl; } ~Notifier() { std::cout << "Notifier::~Notifier" << std::endl; } template boost::signals::connection connect(FUN_TYPE f) { std::cout << "Notifier::connect" << std::endl; return get_signal< mpl::integral_c< MEMBER_ID_TYPE, id > >(m_signals).connect(f); } template int notify(OBJECT_TYPE const *pObj, typename get_member_type< mpl::integral_c< MEMBER_ID_TYPE, id > >::type member_val) { std::cout << "Notifier::notify" << std::endl; boost::optional< int > res = get_signal< mpl::integral_c< MEMBER_ID_TYPE, id > >(m_signals)(pObj, member_val); return res ? res.get() : 0; } }; // how I'd like to use it: struct sth_t { int i; long j; }; class RandomClass { public: enum MemberId { YESNO , STH }; private: bool yesno; sth_t sth; typedef mpl::map< mpl::pair< mpl::integral_c< MemberId, YESNO > , bool > , mpl::pair< mpl::integral_c< MemberId, STH > , sth_t const& > > id_to_member_type_t; typedef Notifier< RandomClass , MemberId , id_to_member_type_t > notifier_t; mutable notifier_t m_notifier; public: RandomClass() : yesno(false) , sth() , m_notifier() { std::cout << "RandomClass::RandomClass" << std::endl; } ~RandomClass() { std::cout << "RandomClass::~RandomClass" << std::endl; } // a client connects by specifying the member id and a callback template < MemberId id, class FUN_TYPE > boost::signals::connection connect(FUN_TYPE f) const { std::cout << "RandomClass::connect" << std::endl; return m_notifier.connect< id >(f); } void setYesNo(bool b) { std::cout << "RandomClass::setYesNo" << std::endl; yesno = b; m_notifier.notify< YESNO >(this, b); } void setSthI(int i) { std::cout << "RandomClass::setSthI" << std::endl; sth.i = i; m_notifier.notify< STH >(this, sth); } void setSthJ(long j) { std::cout << "RandomClass::setSthJ" << std::endl; sth.j = j; m_notifier.notify< STH >(this, sth); } }; struct Client { boost::signals::connection m_con; int handler(RandomClass const *pRandom, bool yesno) { std::cout << "Client::handler: yesno = " << yesno << std::endl; return 1; } explicit Client(RandomClass const &random) { std::cout << "Client::Client" << std::endl; m_con = random.connect< RandomClass::YESNO >(lambda::bind(&Client::handler, this, lambda::_1, lambda::_2)); } ~Client() { std::cout << "Client::~Client" << std::endl; m_con.disconnect(); } }; int handler(RandomClass const *pRandom, sth_t const &sth) { std::cout << "::handler: sth.i = " << sth.i << " sth.j = " << sth.j << std::endl; return 2; } struct Handler { Handler() { std::cout << "Handler::Handler" << std::endl; } Handler(Handler const&) { std::cout << "Handler::Handler(Handler const&)" << std::endl; } ~Handler() { std::cout << "Handler::~Handler" << std::endl; } int operator()(RandomClass const *pRandom, sth_t const &sth) { std::cout << "Handler::operator(): sth.i = " << sth.i << " sth.j = " << sth.j << std::endl; return 3; } }; int main() { std::cout << "" << std::endl; RandomClass r; Client c(r); boost::signals::scoped_connection con1(r.connect< RandomClass::STH >(handler)) , con2(r.connect< RandomClass::STH >(Handler())); r.setYesNo(true); r.setSthI(4711); r.setSthJ(0x0815); std::cout << "" << std::endl; return 0; }