#pragma once #include #include #include #include #include namespace LtsUtils { class IConnection { public: virtual ~IConnection() = default; virtual void connect(Qt::ConnectionType = Qt::AutoConnection) = 0; virtual void disconnect() = 0; }; class DummyConnection : public IConnection { public: void connect(Qt::ConnectionType = Qt::AutoConnection) override {} void disconnect() override {} }; namespace detail { template struct ExtractClass; template struct ExtractClass { using type = T; }; } // namespace detail template class Connection : public IConnection { static_assert(std::is_member_function_pointer_v, "Must be a pointer to method"); static_assert(std::is_member_function_pointer_v, "Must be a pointer to method"); using Emitter = typename detail::ExtractClass::type; using Target = typename detail::ExtractClass::type; static_assert(std::is_base_of_v, "Must be derived from QObject"); static_assert(std::is_base_of_v, "Must be derived from QObject"); public: Connection(Emitter *emitter, Signal signal, Target *target, Slot slot) : m_emitter(emitter), m_signal(signal), m_target(target), m_slot(slot) { Q_ASSERT(emitter); Q_ASSERT(signal); Q_ASSERT(target); Q_ASSERT(slot); } void connect(Qt::ConnectionType connectionType = Qt::AutoConnection) override { Q_ASSERT(!m_connected); m_connected = true; if (!m_emitter || !m_target) return; m_conn = QObject::connect(m_emitter.data(), m_signal, m_target.data(), m_slot, connectionType); Q_ASSERT(m_conn); } void disconnect() override { Q_ASSERT(m_connected); if (m_conn) QObject::disconnect(m_conn); m_connected = false; } private: bool m_connected{false}; QPointer m_emitter; Signal m_signal; QPointer m_target; Slot m_slot; QMetaObject::Connection m_conn; }; template Connection * createConnection(typename detail::ExtractClass::type *emitter, Signal signal, typename detail::ExtractClass::type *target, Slot slot) { return new Connection(emitter, signal, target, slot); } } // namespace LtsUtils