#include #include #include #include // {{{ signals class bad_slot : std::logic_error { public: bad_slot() : std::logic_error("Slot already disconnected") {} }; class connection; template class signal; class signal_base { friend class connection; protected: virtual void disconnectSlot(size_t slot) = 0; }; class connection { template friend class signal; private: signal_base* parent; ssize_t slot; protected: connection(signal_base* parent, ssize_t slot) : parent(parent), slot(slot) {} public: connection(const connection& con) : parent(con.parent), slot(con.slot) {} connection& operator=(const connection& con) { this->parent = con.parent; this->slot = con.slot; return *this; } void disconnect() { if (slot < 0) throw bad_slot(); parent->disconnectSlot(slot); slot = -1; } }; class scoped_connection : connection { public: scoped_connection(const connection& con) : connection(con) {} scoped_connection(const scoped_connection&) = delete; scoped_connection& operator=(const connection& con) { disconnect(); connection::operator=(con); return *this; } ~scoped_connection() { try { disconnect(); } catch (bad_slot) { } } }; template class signal : signal_base { private: std::vector> slots; protected: virtual void disconnectSlot(size_t slot) override { slots[slot].clear(); } public: connection connect(boost::function fn) { for (size_t i = 0; i < slots.size(); ++i) { if (!slots[i]) { slots[i] = fn; return connection(this, i); } } slots.push_back(fn); return connection(this, slots.size() - 1); } R operator()(Args&&... args) { for (size_t idx = 0; idx < slots.size() - 1; ++idx) { if (slots[idx]) { slots[idx](args...); } } if (slots.size() && slots.back()) { return slots.back()(args...); } } }; // }}} void test(int i) { std::cout << "(G) " << i << std::endl; } struct Test { void test(int i) { std::cout << "(C) " << i << std::endl; } }; int main() { signal sig; Test t; connection c = sig.connect(test); connection c2 = sig.connect(boost::bind(&Test::test, &t, _1)); sig(42); c.disconnect(); sig(23); { scoped_connection sc(c2); } sig(1); }