slot signal机制

强颜欢笑 提交于 2020-03-23 12:09:35

有一个比较 经典的实现:
很精简的 signal slot的实现,跨平台。webrtc项目在用,我在自己项目里也用了。
这个源码有2000多行,但是一大半是为了模板适配不同个数的参数的代码,干货不足1000行。

附上代码链接,这个项目只有一个头文件,够小型了吧



Gtalk源码剖析之:sigslot介绍

源码:

// sigslot.h: Signal/Slot classes
// 
// Written by Sarah Thompson (sarah@telergy.com) 2002.
//
// License: Public domain. You are free to use this code however you like, with the proviso that
//          the author takes on no responsibility or liability for any use.
//
// QUICK DOCUMENTATION 
//        
//                (see also the full documentation at http://sigslot.sourceforge.net/)
//
//        #define switches
//            SIGSLOT_PURE_ISO            - Define this to force ISO C++ compliance. This also disables
//                                          all of the thread safety support on platforms where it is 
//                                          available.
//
//            SIGSLOT_USE_POSIX_THREADS    - Force use of Posix threads when using a C++ compiler other than
//                                          gcc on a platform that supports Posix threads. (When using gcc,
//                                          this is the default - use SIGSLOT_PURE_ISO to disable this if 
//                                          necessary)
//
//            SIGSLOT_DEFAULT_MT_POLICY    - Where thread support is enabled, this defaults to multi_threaded_global.
//                                          Otherwise, the default is single_threaded. #define this yourself to
//                                          override the default. In pure ISO mode, anything other than
//                                          single_threaded will cause a compiler error.
//
//        PLATFORM NOTES
//
//            Win32                        - On Win32, the WIN32 symbol must be #defined. Most mainstream
//                                          compilers do this by default, but you may need to define it
//                                          yourself if your build environment is less standard. This causes
//                                          the Win32 thread support to be compiled in and used automatically.
//
//            Unix/Linux/BSD, etc.        - If you're using gcc, it is assumed that you have Posix threads
//                                          available, so they are used automatically. You can override this
//                                          (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using
//                                          something other than gcc but still want to use Posix threads, you
//                                          need to #define SIGSLOT_USE_POSIX_THREADS.
//
//            ISO C++                        - If none of the supported platforms are detected, or if
//                                          SIGSLOT_PURE_ISO is defined, all multithreading support is turned off,
//                                          along with any code that might cause a pure ISO C++ environment to
//                                          complain. Before you ask, gcc -ansi -pedantic won't compile this 
//                                          library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of
//                                          errors that aren't really there. If you feel like investigating this,
//                                          please contact the author.
//
//        
//        THREADING MODES
//
//            single_threaded                - Your program is assumed to be single threaded from the point of view
//                                          of signal/slot usage (i.e. all objects using signals and slots are
//                                          created and destroyed from a single thread). Behaviour if objects are
//                                          destroyed concurrently is undefined (i.e. you'll get the occasional
//                                          segmentation fault/memory exception).
//
//            multi_threaded_global        - Your program is assumed to be multi threaded. Objects using signals and
//                                          slots can be safely created and destroyed from any thread, even when
//                                          connections exist. In multi_threaded_global mode, this is achieved by a
//                                          single global mutex (actually a critical section on Windows because they
//                                          are faster). This option uses less OS resources, but results in more
//                                          opportunities for contention, possibly resulting in more context switches
//                                          than are strictly necessary.
//
//            multi_threaded_local        - Behaviour in this mode is essentially the same as multi_threaded_global,
//                                          except that each signal, and each object that inherits has_slots, all 
//                                          have their own mutex/critical section. In practice, this means that
//                                          mutex collisions (and hence context switches) only happen if they are
//                                          absolutely essential. However, on some platforms, creating a lot of 
//                                          mutexes can slow down the whole OS, so use this option with care.
//
//        USING THE LIBRARY
//
//            See the full documentation at http://sigslot.sourceforge.net/
//
//

#ifndef SIGSLOT_H__
#define SIGSLOT_H__

#include <set>
#include <list>

#if defined(SIGSLOT_PURE_ISO) || (!defined(WIN32) && !defined(__GNUG__) && !defined(SIGSLOT_USE_POSIX_THREADS))
#    define _SIGSLOT_SINGLE_THREADED
#elif defined(WIN32)
#    define _SIGSLOT_HAS_WIN32_THREADS
#    include <windows.h>
#elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS)
#    define _SIGSLOT_HAS_POSIX_THREADS
#    include <pthread.h>
#else
#    define _SIGSLOT_SINGLE_THREADED
#endif

#ifndef SIGSLOT_DEFAULT_MT_POLICY
#    ifdef _SIGSLOT_SINGLE_THREADED
#        define SIGSLOT_DEFAULT_MT_POLICY single_threaded
#    else
#        define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local
#    endif
#endif


namespace sigslot {

    class single_threaded
    {
    public:
        single_threaded()
        {
            ;
        }

        virtual ~single_threaded()
        {
            ;
        }

        virtual void lock()
        {
            ;
        }

        virtual void unlock()
        {
            ;
        }
    };

#ifdef _SIGSLOT_HAS_WIN32_THREADS
    // The multi threading policies only get compiled in if they are enabled.
    class multi_threaded_global
    {
    public:
        multi_threaded_global()
        {
            static bool isinitialised = false;

            if(!isinitialised)
            {
                InitializeCriticalSection(get_critsec());
                isinitialised = true;
            }
        }

        multi_threaded_global(const multi_threaded_global&)
        {
            ;
        }

        virtual ~multi_threaded_global()
        {
            ;
        }

        virtual void lock()
        {
            EnterCriticalSection(get_critsec());
        }

        virtual void unlock()
        {
            LeaveCriticalSection(get_critsec());
        }

    private:
        CRITICAL_SECTION* get_critsec()
        {
            static CRITICAL_SECTION g_critsec;
            return &g_critsec;
        }
    };

    class multi_threaded_local
    {
    public:
        multi_threaded_local()
        {
            InitializeCriticalSection(&m_critsec);
        }

        multi_threaded_local(const multi_threaded_local&)
        {
            InitializeCriticalSection(&m_critsec);
        }

        virtual ~multi_threaded_local()
        {
            DeleteCriticalSection(&m_critsec);
        }

        virtual void lock()
        {
            EnterCriticalSection(&m_critsec);
        }

        virtual void unlock()
        {
            LeaveCriticalSection(&m_critsec);
        }

    private:
        CRITICAL_SECTION m_critsec;
    };
#endif // _SIGSLOT_HAS_WIN32_THREADS

#ifdef _SIGSLOT_HAS_POSIX_THREADS
    // The multi threading policies only get compiled in if they are enabled.
    class multi_threaded_global
    {
    public:
        multi_threaded_global()
        {
            pthread_mutex_init(get_mutex(), NULL);
        }

        multi_threaded_global(const multi_threaded_global&)
        {
            ;
        }

        virtual ~multi_threaded_global()
        {
            ;
        }

        virtual void lock()
        {
            pthread_mutex_lock(get_mutex());
        }

        virtual void unlock()
        {
            pthread_mutex_unlock(get_mutex());
        }

    private:
        pthread_mutex_t* get_mutex()
        {
            static pthread_mutex_t g_mutex;
            return &g_mutex;
        }
    };

    class multi_threaded_local
    {
    public:
        multi_threaded_local()
        {
            pthread_mutex_init(&m_mutex, NULL);
        }

        multi_threaded_local(const multi_threaded_local&)
        {
            pthread_mutex_init(&m_mutex, NULL);
        }

        virtual ~multi_threaded_local()
        {
            pthread_mutex_destroy(&m_mutex);
        }

        virtual void lock()
        {
            pthread_mutex_lock(&m_mutex);
        }

        virtual void unlock()
        {
            pthread_mutex_unlock(&m_mutex);
        }

    private:
        pthread_mutex_t m_mutex;
    };
#endif // _SIGSLOT_HAS_POSIX_THREADS

    template<class mt_policy>
    class lock_block
    {
    public:
        mt_policy *m_mutex;

        lock_block(mt_policy *mtx)
            : m_mutex(mtx)
        {
            m_mutex->lock();
        }

        ~lock_block()
        {
            m_mutex->unlock();
        }
    };

    template<class mt_policy>
    class has_slots;

    template<class mt_policy>
    class _connection_base0
    {
    public:
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emit() = 0;
        virtual _connection_base0* clone() = 0;
        virtual _connection_base0* duplicate(has_slots<mt_policy>* pnewdest) = 0;
    };

    template<class arg1_type, class mt_policy>
    class _connection_base1
    {
    public:
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emit(arg1_type) = 0;
        virtual _connection_base1<arg1_type, mt_policy>* clone() = 0;
        virtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
    };

    template<class arg1_type, class arg2_type, class mt_policy>
    class _connection_base2
    {
    public:
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emit(arg1_type, arg2_type) = 0;
        virtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone() = 0;
        virtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
    };

    template<class arg1_type, class arg2_type, class arg3_type, class mt_policy>
    class _connection_base3
    {
    public:
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emit(arg1_type, arg2_type, arg3_type) = 0;
        virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone() = 0;
        virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy>
    class _connection_base4
    {
    public:
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type) = 0;
        virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone() = 0;
        virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
    class arg5_type, class mt_policy>
    class _connection_base5
    {
    public:
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, 
            arg5_type) = 0;
        virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, mt_policy>* clone() = 0;
        virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
    class arg5_type, class arg6_type, class mt_policy>
    class _connection_base6
    {
    public:
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
            arg6_type) = 0;
        virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, mt_policy>* clone() = 0;
        virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
    class arg5_type, class arg6_type, class arg7_type, class mt_policy>
    class _connection_base7
    {
    public:
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
            arg6_type, arg7_type) = 0;
        virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, arg7_type, mt_policy>* clone() = 0;
        virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
    class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy>
    class _connection_base8
    {
    public:
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,
            arg6_type, arg7_type, arg8_type) = 0;
        virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone() = 0;
        virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest) = 0;
    };

    template<class mt_policy>
    class _signal_base : public mt_policy
    {
    public:
        virtual void slot_disconnect(has_slots<mt_policy>* pslot) = 0;
        virtual void slot_duplicate(const has_slots<mt_policy>* poldslot, has_slots<mt_policy>* pnewslot) = 0;
    };

    template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
    class has_slots : public mt_policy 
    {
    private:
        typedef std::set<_signal_base<mt_policy> *> sender_set;
        typedef sender_set::const_iterator const_iterator;

    public:
        has_slots()
        {
            ;
        }

        has_slots(const has_slots& hs)
            : mt_policy(hs)
        {
            lock_block<mt_policy> lock(this);
            const_iterator it = hs.m_senders.begin();
            const_iterator itEnd = hs.m_senders.end();

            while(it != itEnd)
            {
                (*it)->slot_duplicate(&hs, this);
                m_senders.insert(*it);
                ++it;
            }
        } 

        void signal_connect(_signal_base<mt_policy>* sender)
        {
            lock_block<mt_policy> lock(this);
            m_senders.insert(sender);
        }

        void signal_disconnect(_signal_base<mt_policy>* sender)
        {
            lock_block<mt_policy> lock(this);
            m_senders.erase(sender);
        }

        virtual ~has_slots()
        {
            disconnect_all();
        }

        void disconnect_all()
        {
            lock_block<mt_policy> lock(this);
            const_iterator it = m_senders.begin();
            const_iterator itEnd = m_senders.end();

            while(it != itEnd)
            {
                (*it)->slot_disconnect(this);
                ++it;
            }

            m_senders.erase(m_senders.begin(), m_senders.end());
        }

    private:
        sender_set m_senders;
    };

    template<class mt_policy>
    class _signal_base0 : public _signal_base<mt_policy>
    {
    public:
        typedef std::list<_connection_base0<mt_policy> *>  connections_list;

        _signal_base0()
        {
            ;
        }

        _signal_base0(const _signal_base0& s)
            : _signal_base<mt_policy>(s)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());

                ++it;
            }
        }

        ~_signal_base0()
        {
            disconnect_all();
        }

        void disconnect_all()
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_disconnect(this);
                delete *it;

                ++it;
            }

            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }

        void disconnect(has_slots<mt_policy>* pclass)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == pclass)
                {
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }

                ++it;
            }
        }

        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                connections_list::iterator itNext = it;
                ++itNext;

                if((*it)->getdest() == pslot)
                {
                    m_connected_slots.erase(it);
                    //            delete *it;
                }

                it = itNext;
            }
        }

        void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == oldtarget)
                {
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }

                ++it;
            }
        }

    protected:
        connections_list m_connected_slots;   
    };

    template<class arg1_type, class mt_policy>
    class _signal_base1 : public _signal_base<mt_policy>
    {
    public:
        typedef std::list<_connection_base1<arg1_type, mt_policy> *>  connections_list;

        _signal_base1()
        {
            ;
        }

        _signal_base1(const _signal_base1<arg1_type, mt_policy>& s)
            : _signal_base<mt_policy>(s)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());

                ++it;
            }
        }

        void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == oldtarget)
                {
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }

                ++it;
            }
        }

        ~_signal_base1()
        {
            disconnect_all();
        }

        void disconnect_all()
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_disconnect(this);
                delete *it;

                ++it;
            }

            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }

        void disconnect(has_slots<mt_policy>* pclass)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == pclass)
                {
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }

                ++it;
            }
        }

        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                connections_list::iterator itNext = it;
                ++itNext;

                if((*it)->getdest() == pslot)
                {
                    m_connected_slots.erase(it);
                    //            delete *it;
                }

                it = itNext;
            }
        }


    protected:
        connections_list m_connected_slots;   
    };

    template<class arg1_type, class arg2_type, class mt_policy>
    class _signal_base2 : public _signal_base<mt_policy>
    {
    public:
        typedef std::list<_connection_base2<arg1_type, arg2_type, mt_policy> *>
            connections_list;

        _signal_base2()
        {
            ;
        }

        _signal_base2(const _signal_base2<arg1_type, arg2_type, mt_policy>& s)
            : _signal_base<mt_policy>(s)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());

                ++it;
            }
        }

        void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == oldtarget)
                {
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }

                ++it;
            }
        }

        ~_signal_base2()
        {
            disconnect_all();
        }

        void disconnect_all()
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_disconnect(this);
                delete *it;

                ++it;
            }

            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }

        void disconnect(has_slots<mt_policy>* pclass)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == pclass)
                {
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }

                ++it;
            }
        }

        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                connections_list::iterator itNext = it;
                ++itNext;

                if((*it)->getdest() == pslot)
                {
                    m_connected_slots.erase(it);
                    //            delete *it;
                }

                it = itNext;
            }
        }

    protected:
        connections_list m_connected_slots;   
    };

    template<class arg1_type, class arg2_type, class arg3_type, class mt_policy>
    class _signal_base3 : public _signal_base<mt_policy>
    {
    public:
        typedef std::list<_connection_base3<arg1_type, arg2_type, arg3_type, mt_policy> *>
            connections_list;

        _signal_base3()
        {
            ;
        }

        _signal_base3(const _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>& s)
            : _signal_base<mt_policy>(s)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());

                ++it;
            }
        }

        void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == oldtarget)
                {
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }

                ++it;
            }
        }

        ~_signal_base3()
        {
            disconnect_all();
        }

        void disconnect_all()
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_disconnect(this);
                delete *it;

                ++it;
            }

            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }

        void disconnect(has_slots<mt_policy>* pclass)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == pclass)
                {
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }

                ++it;
            }
        }

        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                connections_list::iterator itNext = it;
                ++itNext;

                if((*it)->getdest() == pslot)
                {
                    m_connected_slots.erase(it);
                    //            delete *it;
                }

                it = itNext;
            }
        }

    protected:
        connections_list m_connected_slots;   
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy>
    class _signal_base4 : public _signal_base<mt_policy>
    {
    public:
        typedef std::list<_connection_base4<arg1_type, arg2_type, arg3_type,
            arg4_type, mt_policy> *>  connections_list;

        _signal_base4()
        {
            ;
        }

        _signal_base4(const _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s)
            : _signal_base<mt_policy>(s)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());

                ++it;
            }
        }

        void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == oldtarget)
                {
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }

                ++it;
            }
        }

        ~_signal_base4()
        {
            disconnect_all();
        }

        void disconnect_all()
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_disconnect(this);
                delete *it;

                ++it;
            }

            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }

        void disconnect(has_slots<mt_policy>* pclass)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == pclass)
                {
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }

                ++it;
            }
        }

        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                connections_list::iterator itNext = it;
                ++itNext;

                if((*it)->getdest() == pslot)
                {
                    m_connected_slots.erase(it);
                    //            delete *it;
                }

                it = itNext;
            }
        }

    protected:
        connections_list m_connected_slots;   
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
    class arg5_type, class mt_policy>
    class _signal_base5 : public _signal_base<mt_policy>
    {
    public:
        typedef std::list<_connection_base5<arg1_type, arg2_type, arg3_type,
            arg4_type, arg5_type, mt_policy> *>  connections_list;

        _signal_base5()
        {
            ;
        }

        _signal_base5(const _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, mt_policy>& s)
            : _signal_base<mt_policy>(s)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());

                ++it;
            }
        }

        void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == oldtarget)
                {
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }

                ++it;
            }
        }

        ~_signal_base5()
        {
            disconnect_all();
        }

        void disconnect_all()
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_disconnect(this);
                delete *it;

                ++it;
            }

            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }

        void disconnect(has_slots<mt_policy>* pclass)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == pclass)
                {
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }

                ++it;
            }
        }

        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                connections_list::iterator itNext = it;
                ++itNext;

                if((*it)->getdest() == pslot)
                {
                    m_connected_slots.erase(it);
                    //            delete *it;
                }

                it = itNext;
            }
        }

    protected:
        connections_list m_connected_slots;   
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
    class arg5_type, class arg6_type, class mt_policy>
    class _signal_base6 : public _signal_base<mt_policy>
    {
    public:
        typedef std::list<_connection_base6<arg1_type, arg2_type, arg3_type, 
            arg4_type, arg5_type, arg6_type, mt_policy> *>  connections_list;

        _signal_base6()
        {
            ;
        }

        _signal_base6(const _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, mt_policy>& s)
            : _signal_base<mt_policy>(s)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());

                ++it;
            }
        }

        void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == oldtarget)
                {
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }

                ++it;
            }
        }

        ~_signal_base6()
        {
            disconnect_all();
        }

        void disconnect_all()
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_disconnect(this);
                delete *it;

                ++it;
            }

            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }

        void disconnect(has_slots<mt_policy>* pclass)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == pclass)
                {
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }

                ++it;
            }
        }

        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                connections_list::iterator itNext = it;
                ++itNext;

                if((*it)->getdest() == pslot)
                {
                    m_connected_slots.erase(it);
                    //            delete *it;
                }

                it = itNext;
            }
        }

    protected:
        connections_list m_connected_slots;   
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
    class arg5_type, class arg6_type, class arg7_type, class mt_policy>
    class _signal_base7 : public _signal_base<mt_policy>
    {
    public:
        typedef std::list<_connection_base7<arg1_type, arg2_type, arg3_type, 
            arg4_type, arg5_type, arg6_type, arg7_type, mt_policy> *>  connections_list;

        _signal_base7()
        {
            ;
        }

        _signal_base7(const _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, arg7_type, mt_policy>& s)
            : _signal_base<mt_policy>(s)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());

                ++it;
            }
        }

        void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == oldtarget)
                {
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }

                ++it;
            }
        }

        ~_signal_base7()
        {
            disconnect_all();
        }

        void disconnect_all()
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_disconnect(this);
                delete *it;

                ++it;
            }

            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }

        void disconnect(has_slots<mt_policy>* pclass)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == pclass)
                {
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }

                ++it;
            }
        }

        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                connections_list::iterator itNext = it;
                ++itNext;

                if((*it)->getdest() == pslot)
                {
                    m_connected_slots.erase(it);
                    //            delete *it;
                }

                it = itNext;
            }
        }

    protected:
        connections_list m_connected_slots;   
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
    class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy>
    class _signal_base8 : public _signal_base<mt_policy>
    {
    public:
        typedef std::list<_connection_base8<arg1_type, arg2_type, arg3_type, 
            arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy> *>
            connections_list;

        _signal_base8()
        {
            ;
        }

        _signal_base8(const _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s)
            : _signal_base<mt_policy>(s)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = s.m_connected_slots.begin();
            connections_list::const_iterator itEnd = s.m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());

                ++it;
            }
        }

        void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == oldtarget)
                {
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }

                ++it;
            }
        }

        ~_signal_base8()
        {
            disconnect_all();
        }

        void disconnect_all()
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                (*it)->getdest()->signal_disconnect(this);
                delete *it;

                ++it;
            }

            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }

        void disconnect(has_slots<mt_policy>* pclass)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                if((*it)->getdest() == pclass)
                {
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }

                ++it;
            }
        }

        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
            lock_block<mt_policy> lock(this);
            connections_list::iterator it = m_connected_slots.begin();
            connections_list::iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                connections_list::iterator itNext = it;
                ++itNext;

                if((*it)->getdest() == pslot)
                {
                    m_connected_slots.erase(it);
                    //            delete *it;
                }

                it = itNext;
            }
        }

    protected:
        connections_list m_connected_slots;   
    };


    template<class dest_type, class mt_policy>
    class _connection0 : public _connection_base0<mt_policy>
    {
    public:
        _connection0()
        {
            pobject = NULL;
            pmemfun = NULL;
        }

        _connection0(dest_type* pobject, void (dest_type::*pmemfun)())
        {
            m_pobject = pobject;
            m_pmemfun = pmemfun;
        }

        virtual _connection_base0<mt_policy>* clone()
        {
            return new _connection0<dest_type, mt_policy>(*this);
        }

        virtual _connection_base0<mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
        {
            return new _connection0<dest_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
        }

        virtual void emit()
        {
            (m_pobject->*m_pmemfun)();
        }

        virtual has_slots<mt_policy>* getdest() const
        {
            return m_pobject;
        }

    private:
        dest_type* m_pobject;
        void (dest_type::* m_pmemfun)();
    };

    template<class dest_type, class arg1_type, class mt_policy>
    class _connection1 : public _connection_base1<arg1_type, mt_policy>
    {
    public:
        _connection1()
        {
            pobject = NULL;
            pmemfun = NULL;
        }

        _connection1(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type))
        {
            m_pobject = pobject;
            m_pmemfun = pmemfun;
        }

        virtual _connection_base1<arg1_type, mt_policy>* clone()
        {
            return new _connection1<dest_type, arg1_type, mt_policy>(*this);
        }

        virtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
        {
            return new _connection1<dest_type, arg1_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
        }

        virtual void emit(arg1_type a1)
        {
            (m_pobject->*m_pmemfun)(a1);
        }

        virtual has_slots<mt_policy>* getdest() const
        {
            return m_pobject;
        }

    private:
        dest_type* m_pobject;
        void (dest_type::* m_pmemfun)(arg1_type);
    };

    template<class dest_type, class arg1_type, class arg2_type, class mt_policy>
    class _connection2 : public _connection_base2<arg1_type, arg2_type, mt_policy>
    {
    public:
        _connection2()
        {
            pobject = NULL;
            pmemfun = NULL;
        }

        _connection2(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
            arg2_type))
        {
            m_pobject = pobject;
            m_pmemfun = pmemfun;
        }

        virtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone()
        {
            return new _connection2<dest_type, arg1_type, arg2_type, mt_policy>(*this);
        }

        virtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
        {
            return new _connection2<dest_type, arg1_type, arg2_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
        }

        virtual void emit(arg1_type a1, arg2_type a2)
        {
            (m_pobject->*m_pmemfun)(a1, a2);
        }

        virtual has_slots<mt_policy>* getdest() const
        {
            return m_pobject;
        }

    private:
        dest_type* m_pobject;
        void (dest_type::* m_pmemfun)(arg1_type, arg2_type);
    };

    template<class dest_type, class arg1_type, class arg2_type, class arg3_type, class mt_policy>
    class _connection3 : public _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>
    {
    public:
        _connection3()
        {
            pobject = NULL;
            pmemfun = NULL;
        }

        _connection3(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
            arg2_type, arg3_type))
        {
            m_pobject = pobject;
            m_pmemfun = pmemfun;
        }

        virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone()
        {
            return new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>(*this);
        }

        virtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
        {
            return new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
        }

        virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3)
        {
            (m_pobject->*m_pmemfun)(a1, a2, a3);
        }

        virtual has_slots<mt_policy>* getdest() const
        {
            return m_pobject;
        }

    private:
        dest_type* m_pobject;
        void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type);
    };

    template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
    class arg4_type, class mt_policy>
    class _connection4 : public _connection_base4<arg1_type, arg2_type,
        arg3_type, arg4_type, mt_policy>
    {
    public:
        _connection4()
        {
            pobject = NULL;
            pmemfun = NULL;
        }

        _connection4(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
            arg2_type, arg3_type, arg4_type))
        {
            m_pobject = pobject;
            m_pmemfun = pmemfun;
        }

        virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone()
        {
            return new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(*this);
        }

        virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
        {
            return new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
        }

        virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, 
            arg4_type a4)
        {
            (m_pobject->*m_pmemfun)(a1, a2, a3, a4);
        }

        virtual has_slots<mt_policy>* getdest() const
        {
            return m_pobject;
        }

    private:
        dest_type* m_pobject;
        void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type,
            arg4_type);
    };

    template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
    class arg4_type, class arg5_type, class mt_policy>
    class _connection5 : public _connection_base5<arg1_type, arg2_type,
        arg3_type, arg4_type, arg5_type, mt_policy>
    {
    public:
        _connection5()
        {
            pobject = NULL;
            pmemfun = NULL;
        }

        _connection5(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
            arg2_type, arg3_type, arg4_type, arg5_type))
        {
            m_pobject = pobject;
            m_pmemfun = pmemfun;
        }

        virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, 
            arg5_type, mt_policy>* clone()
        {
            return new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
                arg5_type, mt_policy>(*this);
        }

        virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, 
            arg5_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
        {
            return new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
                arg5_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
        }

        virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
            arg5_type a5)
        {
            (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5);
        }

        virtual has_slots<mt_policy>* getdest() const
        {
            return m_pobject;
        }

    private:
        dest_type* m_pobject;
        void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type);
    };

    template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
    class arg4_type, class arg5_type, class arg6_type, class mt_policy>
    class _connection6 : public _connection_base6<arg1_type, arg2_type,
        arg3_type, arg4_type, arg5_type, arg6_type, mt_policy>
    {
    public:
        _connection6()
        {
            pobject = NULL;
            pmemfun = NULL;
        }

        _connection6(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
            arg2_type, arg3_type, arg4_type, arg5_type, arg6_type))
        {
            m_pobject = pobject;
            m_pmemfun = pmemfun;
        }

        virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type, 
            arg5_type, arg6_type, mt_policy>* clone()
        {
            return new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
                arg5_type, arg6_type, mt_policy>(*this);
        }

        virtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type, 
            arg5_type, arg6_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
        {
            return new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
                arg5_type, arg6_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
        }

        virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
            arg5_type a5, arg6_type a6)
        {
            (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6);
        }

        virtual has_slots<mt_policy>* getdest() const
        {
            return m_pobject;
        }

    private:
        dest_type* m_pobject;
        void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type);
    };

    template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
    class arg4_type, class arg5_type, class arg6_type, class arg7_type, class mt_policy>
    class _connection7 : public _connection_base7<arg1_type, arg2_type,
        arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>
    {
    public:
        _connection7()
        {
            pobject = NULL;
            pmemfun = NULL;
        }

        _connection7(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
            arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type))
        {
            m_pobject = pobject;
            m_pmemfun = pmemfun;
        }

        virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type, 
            arg5_type, arg6_type, arg7_type, mt_policy>* clone()
        {
            return new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
                arg5_type, arg6_type, arg7_type, mt_policy>(*this);
        }

        virtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type, 
            arg5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
        {
            return new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
                arg5_type, arg6_type, arg7_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
        }

        virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
            arg5_type a5, arg6_type a6, arg7_type a7)
        {
            (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7);
        }

        virtual has_slots<mt_policy>* getdest() const
        {
            return m_pobject;
        }

    private:
        dest_type* m_pobject;
        void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, arg7_type);
    };

    template<class dest_type, class arg1_type, class arg2_type, class arg3_type,
    class arg4_type, class arg5_type, class arg6_type, class arg7_type, 
    class arg8_type, class mt_policy>
    class _connection8 : public _connection_base8<arg1_type, arg2_type,
        arg3_type, arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>
    {
    public:
        _connection8()
        {
            pobject = NULL;
            pmemfun = NULL;
        }

        _connection8(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,
            arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, 
            arg7_type, arg8_type))
        {
            m_pobject = pobject;
            m_pmemfun = pmemfun;
        }

        virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type, 
            arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone()
        {
            return new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
                arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>(*this);
        }

        virtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type, 
            arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
        {
            return new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, 
                arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
        }

        virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
            arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
        {
            (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7, a8);
        }

        virtual has_slots<mt_policy>* getdest() const
        {
            return m_pobject;
        }

    private:
        dest_type* m_pobject;
        void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, arg7_type, arg8_type);
    };

    template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
    class signal0 : public _signal_base0<mt_policy>
    {
    public:
        signal0()
        {
            ;
        }

        signal0(const signal0<mt_policy>& s)
            : _signal_base0<mt_policy>(s)
        {
            ;
        }

        template<class desttype>
            void connect(desttype* pclass, void (desttype::*pmemfun)())
        {
            lock_block<mt_policy> lock(this);
            _connection0<desttype, mt_policy>* conn = 
                new _connection0<desttype, mt_policy>(pclass, pmemfun);
            m_connected_slots.push_back(conn);
            pclass->signal_connect(this);
        }

        void emit()
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit();

                it = itNext;
            }
        }

        void operator()()
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit();

                it = itNext;
            }
        }
    };

    template<class arg1_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
    class signal1 : public _signal_base1<arg1_type, mt_policy>
    {
    public:
        signal1()
        {
            ;
        }

        signal1(const signal1<arg1_type, mt_policy>& s)
            : _signal_base1<arg1_type, mt_policy>(s)
        {
            ;
        }

        template<class desttype>
            void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type))
        {
            lock_block<mt_policy> lock(this);
            _connection1<desttype, arg1_type, mt_policy>* conn = 
                new _connection1<desttype, arg1_type, mt_policy>(pclass, pmemfun);
            m_connected_slots.push_back(conn);
            pclass->signal_connect(this);
        }

        void emit(arg1_type a1)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1);

                it = itNext;
            }
        }

        void operator()(arg1_type a1)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1);

                it = itNext;
            }
        }
    };

    template<class arg1_type, class arg2_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
    class signal2 : public _signal_base2<arg1_type, arg2_type, mt_policy>
    {
    public:
        signal2()
        {
            ;
        }

        signal2(const signal2<arg1_type, arg2_type, mt_policy>& s)
            : _signal_base2<arg1_type, arg2_type, mt_policy>(s)
        {
            ;
        }

        template<class desttype>
            void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
            arg2_type))
        {
            lock_block<mt_policy> lock(this);
            _connection2<desttype, arg1_type, arg2_type, mt_policy>* conn = new
                _connection2<desttype, arg1_type, arg2_type, mt_policy>(pclass, pmemfun);
            m_connected_slots.push_back(conn);
            pclass->signal_connect(this);
        }

        void emit(arg1_type a1, arg2_type a2)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2);

                it = itNext;
            }
        }

        void operator()(arg1_type a1, arg2_type a2)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2);

                it = itNext;
            }
        }
    };

    template<class arg1_type, class arg2_type, class arg3_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
    class signal3 : public _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>
    {
    public:
        signal3()
        {
            ;
        }

        signal3(const signal3<arg1_type, arg2_type, arg3_type, mt_policy>& s)
            : _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>(s)
        {
            ;
        }

        template<class desttype>
            void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
            arg2_type, arg3_type))
        {
            lock_block<mt_policy> lock(this);
            _connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>* conn = 
                new _connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>(pclass,
                pmemfun);
            m_connected_slots.push_back(conn);
            pclass->signal_connect(this);
        }

        void emit(arg1_type a1, arg2_type a2, arg3_type a3)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2, a3);

                it = itNext;
            }
        }

        void operator()(arg1_type a1, arg2_type a2, arg3_type a3)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2, a3);

                it = itNext;
            }
        }
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
    class signal4 : public _signal_base4<arg1_type, arg2_type, arg3_type,
        arg4_type, mt_policy>
    {
    public:
        signal4()
        {
            ;
        }

        signal4(const signal4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s)
            : _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(s)
        {
            ;
        }

        template<class desttype>
            void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
            arg2_type, arg3_type, arg4_type))
        {
            lock_block<mt_policy> lock(this);
            _connection4<desttype, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>*
                conn = new _connection4<desttype, arg1_type, arg2_type, arg3_type,
                arg4_type, mt_policy>(pclass, pmemfun);
            m_connected_slots.push_back(conn);
            pclass->signal_connect(this);
        }

        void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2, a3, a4);

                it = itNext;
            }
        }

        void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2, a3, a4);

                it = itNext;
            }
        }
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
    class arg5_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
    class signal5 : public _signal_base5<arg1_type, arg2_type, arg3_type,
        arg4_type, arg5_type, mt_policy>
    {
    public:
        signal5()
        {
            ;
        }

        signal5(const signal5<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, mt_policy>& s)
            : _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, mt_policy>(s)
        {
            ;
        }

        template<class desttype>
            void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
            arg2_type, arg3_type, arg4_type, arg5_type))
        {
            lock_block<mt_policy> lock(this);
            _connection5<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
                arg5_type, mt_policy>* conn = new _connection5<desttype, arg1_type, arg2_type,
                arg3_type, arg4_type, arg5_type, mt_policy>(pclass, pmemfun);
            m_connected_slots.push_back(conn);
            pclass->signal_connect(this);
        }

        void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
            arg5_type a5)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2, a3, a4, a5);

                it = itNext;
            }
        }

        void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
            arg5_type a5)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2, a3, a4, a5);

                it = itNext;
            }
        }
    };


    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
    class arg5_type, class arg6_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
    class signal6 : public _signal_base6<arg1_type, arg2_type, arg3_type,
        arg4_type, arg5_type, arg6_type, mt_policy>
    {
    public:
        signal6()
        {
            ;
        }

        signal6(const signal6<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, mt_policy>& s)
            : _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, mt_policy>(s)
        {
            ;
        }

        template<class desttype>
            void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
            arg2_type, arg3_type, arg4_type, arg5_type, arg6_type))
        {
            lock_block<mt_policy> lock(this);
            _connection6<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
                arg5_type, arg6_type, mt_policy>* conn = 
                new _connection6<desttype, arg1_type, arg2_type, arg3_type,
                arg4_type, arg5_type, arg6_type, mt_policy>(pclass, pmemfun);
            m_connected_slots.push_back(conn);
            pclass->signal_connect(this);
        }

        void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
            arg5_type a5, arg6_type a6)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2, a3, a4, a5, a6);

                it = itNext;
            }
        }

        void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
            arg5_type a5, arg6_type a6)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2, a3, a4, a5, a6);

                it = itNext;
            }
        }
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
    class arg5_type, class arg6_type, class arg7_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
    class signal7 : public _signal_base7<arg1_type, arg2_type, arg3_type,
        arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>
    {
    public:
        signal7()
        {
            ;
        }

        signal7(const signal7<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, arg7_type, mt_policy>& s)
            : _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, arg7_type, mt_policy>(s)
        {
            ;
        }

        template<class desttype>
            void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
            arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, 
            arg7_type))
        {
            lock_block<mt_policy> lock(this);
            _connection7<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
                arg5_type, arg6_type, arg7_type, mt_policy>* conn = 
                new _connection7<desttype, arg1_type, arg2_type, arg3_type,
                arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>(pclass, pmemfun);
            m_connected_slots.push_back(conn);
            pclass->signal_connect(this);
        }

        void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
            arg5_type a5, arg6_type a6, arg7_type a7)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2, a3, a4, a5, a6, a7);

                it = itNext;
            }
        }

        void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
            arg5_type a5, arg6_type a6, arg7_type a7)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2, a3, a4, a5, a6, a7);

                it = itNext;
            }
        }
    };

    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
    class arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
    class signal8 : public _signal_base8<arg1_type, arg2_type, arg3_type,
        arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>
    {
    public:
        signal8()
        {
            ;
        }

        signal8(const signal8<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s)
            : _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,
            arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>(s)
        {
            ;
        }

        template<class desttype>
            void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,
            arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, 
            arg7_type, arg8_type))
        {
            lock_block<mt_policy> lock(this);
            _connection8<desttype, arg1_type, arg2_type, arg3_type, arg4_type,
                arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>* conn = 
                new _connection8<desttype, arg1_type, arg2_type, arg3_type,
                arg4_type, arg5_type, arg6_type, arg7_type, 
                arg8_type, mt_policy>(pclass, pmemfun);
            m_connected_slots.push_back(conn);
            pclass->signal_connect(this);
        }

        void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
            arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8);

                it = itNext;
            }
        }

        void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,
            arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)
        {
            lock_block<mt_policy> lock(this);
            connections_list::const_iterator itNext, it = m_connected_slots.begin();
            connections_list::const_iterator itEnd = m_connected_slots.end();

            while(it != itEnd)
            {
                itNext = it;
                ++itNext;

                (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8);

                it = itNext;
            }
        }
    };

}; // namespace sigslot

#endif // SIGSLOT_H__

 

http://www.cppblog.com/cyt/archive/2005/10/08/591.html

 

http://blog.csdn.net/hhyttppd/article/details/4192668

 

 

Qt源码分析之信号和槽机制

Qt的信号和槽机制是Qt的一大特点,实际上这是和MFC中的消息映射机制相似的东西,要完成的事情也差不多,就是发送一个消息然后让其它窗口响应,当然,这里的消息是广义的
说法,简单点说就是如何在一个类的一个函数中触发另一个类的另一个函数调用,而且还要把相关的参数传递过去.好像这和回调函数也有点关系,但是消息机制可比回调函数有用
多了,也复杂多了

MFC中的消息机制没有采用C++中的虚函数机制,原因是消息太多,虚函数开销太大.在Qt中也没有采用C++中的虚函数机制,原因与此相同.其实这里还有更深层次上的原因,大体说来,
多态的底层实现机制只有两种,一种是按照名称查表,一种是按照位置查表,两种方式各有利弊,而C++的虚函数机制无条件的采用了后者,导致的问题就是在子类很少重载基类实现
的时候开销太大,再加上象界面编程这样子类众多的情况,基本上C++的虚函数机制就废掉了,于是各家库的编写者就只好自谋生路了,说到底,这确实是C++语言本身的缺陷

示例代码:
#include <QApplication>
#include <QPushButton>
#include <QPointer>

int main(int argc, char *argv[])
{
 QApplication app(argc, argv);

    QPushButton quit("Quit");
    quit.resize(100, 30);
    quit.show();
  QObject::connect(&quit, SIGNAL(clicked()), &app, SLOT(quit()));
    
    return app.exec();
}

这里主要是看QPushButton的clicked()信号和app的quit()槽如何连接?又是如何响应?
前面已经说过了,Qt的信号槽机制其实就是按照名称查表,因此这里的首要问题是如何构造这个表?
和C++虚函数表机制类似的,在Qt中,这个表就是元数据表,Qt中的元数据表最大的作用就是支持信号槽机制,当然,也可以在此基础上扩展出更多的功能,因为
元数据是我们可以直接访问到的,不再是象虚函数表那样被编译器遮遮掩掩的藏了起来,不过Qt似乎还没有完全发挥元数据的能力,动态属性,反射之类的机制好像还没有

任何从QObject派生的类都包含了自己的元数据模型,一般是通过宏Q_OBJECT定义的
#define Q_OBJECT /
public: /
    static const QMetaObject staticMetaObject; /
    virtual const QMetaObject *metaObject() const; /
    virtual void *qt_metacast(const char *); /
    QT_TR_FUNCTIONS /
    virtual int qt_metacall(QMetaObject::Call, int, void **); /
private:

首先声明了一个QMetaObject类型的静态成员变量,这就是元数据的数据结构

struct Q_CORE_EXPORT QMetaObject
{
...
    struct { // private data
        const QMetaObject *superdata;
        const char *stringdata;
        const uint *data;
        const QMetaObject **extradata;
    } d;
}
QMetaObject中有一个嵌套类封装了所有的数据
        const QMetaObject *superdata;//这是元数据代表的类的基类的元数据
        const char *stringdata;//这是元数据的签名标记
        const uint *data;//这是元数据的索引数组的指针
        const QMetaObject **extradata;//这是扩展元数据表的指针,一般是不用的       

这里的三个虚函数metaObject,qt_metacast,qt_metacall是在moc文件中定义的
metaObject的作用是得到元数据表指针
qt_metacast的作用是根据签名得到相关结构的指针,注意它返回的可是void*指针
qt_metacall的作用是查表然后调用调用相关的函数

宏QT_TR_FUNCTIONS是和翻译相关的
#  define QT_TR_FUNCTIONS /
    static inline QString tr(const char *s, const char *c = 0) /
        { return staticMetaObject.tr(s, c); }

好了,看看实际的例子吧:

QPushButton的元数据表如下:
static const uint qt_meta_data_QPushButton[] = {

 // content:
       1,       // revision
       0,       // classname
       0,    0, // classinfo
       2,   10, // methods
       3,   20, // properties
       0,    0, // enums/sets

 // slots: signature, parameters, type, tag, flags
      13,   12,   12,   12, 0x0a,
      24,   12,   12,   12, 0x08,

 // properties: name, type, flags
      44,   39, 0x01095103,
      56,   39, 0x01095103,
      64,   39, 0x01095103,

       0        // eod
};

static const char qt_meta_stringdata_QPushButton[] = {
    "QPushButton/0/0showMenu()/0popupPressed()/0bool/0autoDefault/0default/0"
    "flat/0"
};

const QMetaObject QPushButton::staticMetaObject = {
    { &QAbstractButton::staticMetaObject, qt_meta_stringdata_QPushButton,
      qt_meta_data_QPushButton, 0 }
};

在这里我们看到了静态成员staticMetaObject被填充了
        const QMetaObject *superdata;//这是元数据代表的类的基类的元数据,被填充为基类的元数据指针&QAbstractButton::staticMetaObject
        const char *stringdata;//这是元数据的签名标记,被填充为qt_meta_stringdata_QPushButton
        const uint *data;//这是元数据的索引数组的指针,被填充为qt_meta_data_QPushButton
        const QMetaObject **extradata;//这是扩展元数据表的指针,一般是不用的,被填充为0

首先应该看qt_meta_data_QPushButton,因为这里是元数据的主要数据,它被填充为一个整数数组,正因为这里只有整数,不能有任何字符串存在,因此才有
qt_meta_stringdata_QPushButton发挥作用的机会,可以说真正的元数据应该是qt_meta_data_QPushButton加上qt_meta_stringdata_QPushButton,那么为什么
不把这两个东西合在一起呢?估计是两者都不是定长的结构,合在一起反而麻烦吧

qt_meta_data_QPushButton实际上是以以下结构开头的

struct QMetaObjectPrivate
{
    int revision;
    int className;
    int classInfoCount, classInfoData;
    int methodCount, methodData;
    int propertyCount, propertyData;
    int enumeratorCount, enumeratorData;
};

一般使用中是直接使用以下函数做个转换
static inline const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }

这种转换怎么看都有些黑客的味道,这确实是十足的C风格

再结合实际的数据看一看
static const uint qt_meta_data_QPushButton[] = {

 // content:
       1,       // revision  版本号是1
       0,       // classname 类名存储在qt_meta_stringdata_QPushButton中,索引是0,因此就是QPushButton了
       0,    0, // classinfo  类信息数量为0,数据也是0
       2,   10, // methods  QPushButton有2个自定义方法,方法数据存储在qt_meta_data_QPushButton中,索引是10,就是下面的slots:开始的地方
       3,   20, // properties QPushButton有3个自定义属性,属性数据存储在qt_meta_data_QPushButton中,索引是20,就是下面的properties:开始的地方
       0,    0, // enums/sets QPushButton没有自定义的枚举

 // slots: signature, parameters, type, tag, flags
      13,   12,   12,   12, 0x0a,
      第一个自定义方法的签名存储在qt_meta_data_QPushButton中,索引是13,就是showMenu()了
      24,   12,   12,   12, 0x08,
      第二个自定义方法的签名存储在qt_meta_data_QPushButton中,索引是24,popupPressed()了

 // properties: name, type, flags
      44,   39, 0x01095103,   
      第一个自定义属性的签名存储在qt_meta_data_QPushButton中,索引是44,就是autoDefault了
      第一个自定义属性的类型存储在qt_meta_data_QPushButton中,索引是39,就是bool
      56,   39, 0x01095103,   
      第二个自定义属性的签名存储在qt_meta_data_QPushButton中,索引是56,就是default了
      第二个自定义属性的类型存储在qt_meta_data_QPushButton中,索引是39,就是bool
      64,   39, 0x01095103,   
      第三个自定义属性的签名存储在qt_meta_data_QPushButton中,索引是64,就是flat了
      第三个自定义属性的类型存储在qt_meta_data_QPushButton中,索引是39,就是bool

       0        // eod 元数据的结束标记
};

static const char qt_meta_stringdata_QPushButton[] = {
    "QPushButton/0/0showMenu()/0popupPressed()/0bool/0autoDefault/0default/0"
    "flat/0"
};

QPushButton//showMenu()/popupPressed()/bool/autoDefault/default/flat/
这里把/0直接替换为/是为了数数的方便

当然我们还可以看看QPushButton的基类QAbstractButton的元数据
static const uint qt_meta_data_QAbstractButton[] = {

 // content:
       1,       // revision
       0,       // classname
       0,    0, // classinfo
      12,   10, // methods
       9,   70, // properties
       0,    0, // enums/sets

 // signals: signature, parameters, type, tag, flags
      17,   16,   16,   16, 0x05,
      27,   16,   16,   16, 0x05,
      46,   38,   16,   16, 0x05,
      60,   16,   16,   16, 0x25,
      70,   38,   16,   16, 0x05,

 // slots: signature, parameters, type, tag, flags
      89,   84,   16,   16, 0x0a,
     113,  108,   16,   16, 0x0a,
     131,   16,   16,   16, 0x2a,
     146,   16,   16,   16, 0x0a,
     154,   16,   16,   16, 0x0a,
     163,   16,   16,   16, 0x0a,
     182,  180,   16,   16, 0x1a,

 // properties: name, type, flags
     202,  194, 0x0a095103,
     213,  207, 0x45095103,
     224,  218, 0x15095103,
     246,  233, 0x4c095103,
     260,  255, 0x01095103,
      38,  255, 0x01195103,
     270,  255, 0x01095103,
     281,  255, 0x01095103,
     295,  255, 0x01094103,

       0        // eod
};

static const char qt_meta_stringdata_QAbstractButton[] = {
    "QAbstractButton/0/0pressed()/0released()/0checked/0clicked(bool)/0"
    "clicked()/0toggled(bool)/0size/0setIconSize(QSize)/0msec/0"
    "animateClick(int)/0animateClick()/0click()/0toggle()/0setChecked(bool)/0"
    "b/0setOn(bool)/0QString/0text/0QIcon/0icon/0QSize/0iconSize/0"
    "QKeySequence/0shortcut/0bool/0checkable/0autoRepeat/0autoExclusive/0"
    "down/0"
};

QAbstractButton00pressed()0released()0checked0clicked(bool)0clicked()0toggled(bool)0size0setIconSize(QSize)0msec0animateClick(int)0animateClick()0click()0toggle()0setChecked(bool)0b0setOn(bool)0QString0text0QIcon0icon0QSize0iconSize0QKeySequence0shortcut0bool0checkable0autoRepeat0autoExclusive0down0

基本上都是大同小异的

  QObject::connect(&quit, SIGNAL(clicked()), &app, SLOT(quit()));
下面开始看信号和槽连接的源码了

// connect的源码
connect函数是连接信号和槽的桥梁,非常关键
bool QObject::connect(const QObject *sender, const char *signal,
                      const QObject *receiver, const char *method,
                      Qt::ConnectionType type)
{
#ifndef QT_NO_DEBUG
    bool warnCompat = true;
#endif
    if (type == Qt::AutoCompatConnection) {
        type = Qt::AutoConnection;
#ifndef QT_NO_DEBUG
        warnCompat = false;
#endif
    }

 // 不允许空输入
    if (sender == 0 || receiver == 0 || signal == 0 || method == 0) {
#ifndef QT_NO_DEBUG
        qWarning("Object::connect: Cannot connect %s::%s to %s::%s",
                 sender ? sender->metaObject()->className() : "(null)",
                 signal ? signal+1 : "(null)",
                 receiver ? receiver->metaObject()->className() : "(null)",
                 method ? method+1 : "(null)");
#endif
        return false;
    }
    QByteArray tmp_signal_name;

#ifndef QT_NO_DEBUG
 // 检查是否是信号标记
    if (!check_signal_macro(sender, signal, "connect", "bind"))
        return false;
#endif
 // 得到元数据类
    const QMetaObject *smeta = sender->metaObject();
    ++signal; //skip code跳过信号标记,直接得到信号标识
 // 得到信号的索引
    int signal_index = smeta->indexOfSignal(signal);
    if (signal_index < 0) {
        // check for normalized signatures
        tmp_signal_name = QMetaObject::normalizedSignature(signal).prepend(*(signal - 1));
        signal = tmp_signal_name.constData() + 1;
        signal_index = smeta->indexOfSignal(signal);
        if (signal_index < 0) {
#ifndef QT_NO_DEBUG
            err_method_notfound(QSIGNAL_CODE, sender, signal, "connect");
            err_info_about_objects("connect", sender, receiver);
#endif
            return false;
        }
    }

    QByteArray tmp_method_name;
    int membcode = method[0] - '0';

#ifndef QT_NO_DEBUG
 // 检查是否是槽,用QSLOT_CODE 1标记
    if (!check_method_code(membcode, receiver, method, "connect"))
        return false;
#endif
    ++method; // skip code

  // 得到元数据类
    const QMetaObject *rmeta = receiver->metaObject();
    int method_index = -1;
 // 这里是一个case,信号即可以和信号连接也可以和槽连接
    switch (membcode) {
    case QSLOT_CODE:
  // 得到槽的索引
        method_index = rmeta->indexOfSlot(method);
        break;
    case QSIGNAL_CODE:
  // 得到信号的索引
        method_index = rmeta->indexOfSignal(method);
        break;
    }
    if (method_index < 0) {
        // check for normalized methods
        tmp_method_name = QMetaObject::normalizedSignature(method);
        method = tmp_method_name.constData();
        switch (membcode) {
        case QSLOT_CODE:
            method_index = rmeta->indexOfSlot(method);
            break;
        case QSIGNAL_CODE:
            method_index = rmeta->indexOfSignal(method);
            break;
        }
    }

    if (method_index < 0) {
#ifndef QT_NO_DEBUG
        err_method_notfound(membcode, receiver, method, "connect");
        err_info_about_objects("connect", sender, receiver);
#endif
        return false;
    }
#ifndef QT_NO_DEBUG
 // 检查参数,信号和槽的参数必须一致,槽的参数也可以小于信号的参数
    if (!QMetaObject::checkConnectArgs(signal, method)) {
        qWarning("Object::connect: Incompatible sender/receiver arguments"
                 "/n/t%s::%s --> %s::%s",
                 sender->metaObject()->className(), signal,
                 receiver->metaObject()->className(), method);
        return false;
    }
#endif

    int *types = 0;
    if (type == Qt::QueuedConnection
            && !(types = ::queuedConnectionTypes(smeta->method(signal_index).parameterTypes())))
        return false;

#ifndef QT_NO_DEBUG
    {
  // 得到方法的元数据
        QMetaMethod smethod = smeta->method(signal_index);
        QMetaMethod rmethod = rmeta->method(method_index);
        if (warnCompat) {
            if(smethod.attributes() & QMetaMethod::Compatibility) {
                if (!(rmethod.attributes() & QMetaMethod::Compatibility))
                    qWarning("Object::connect: Connecting from COMPAT signal (%s::%s).", smeta->className(), signal);
            } else if(rmethod.attributes() & QMetaMethod::Compatibility && membcode != QSIGNAL_CODE) {
                qWarning("Object::connect: Connecting from %s::%s to COMPAT slot (%s::%s).",
                         smeta->className(), signal, rmeta->className(), method);
            }
        }
    }
#endif
 // 调用元数据类的连接
    QMetaObject::connect(sender, signal_index, receiver, method_index, type, types);
 // 发送连接的通知,现在的实现是空的
    const_cast<QObject*>(sender)->connectNotify(signal - 1);
    return true;
}

检查信号标记其实比较简单,就是用signal的第一个字符和用QSIGNAL_CODE=2的标记比较而已
static bool check_signal_macro(const QObject *sender, const char *signal,
                                const char *func, const char *op)
{
    int sigcode = (int)(*signal) - '0';
    if (sigcode != QSIGNAL_CODE) {
        if (sigcode == QSLOT_CODE)
            qWarning("Object::%s: Attempt to %s non-signal %s::%s",
                     func, op, sender->metaObject()->className(), signal+1);
        else
            qWarning("Object::%s: Use the SIGNAL macro to %s %s::%s",
                     func, op, sender->metaObject()->className(), signal);
        return false;
    }
    return true;
}

得到信号的索引实际上要依次找每个基类的元数据,得到的偏移也是所有元数据表加在一起后的一个索引
int QMetaObject::indexOfSignal(const char *signal) const
{
    int i = -1;
    const QMetaObject *m = this;
    while (m && i < 0) {
  // 根据方法的数目倒序的查找
        for (i = priv(m->d.data)->methodCount-1; i >= 0; --i)
   // 得到该方法的类型
            if ((m->d.data[priv(m->d.data)->methodData + 5*i + 4] & MethodTypeMask) == MethodSignal
                && strcmp(signal, m->d.stringdata
       // 得到方法名称的偏移
                          + m->d.data[priv(m->d.data)->methodData + 5*i]) == 0) {
        //如果找到了正确的方法,再增加所有基类的方法偏移量
                i += m->methodOffset();
                break;
            }
   // 在父类中继续找
        m = m->d.superdata;
    }
#ifndef QT_NO_DEBUG
 // 判断是否于基类中的冲突
    if (i >= 0 && m && m->d.superdata) {
        int conflict = m->d.superdata->indexOfMethod(signal);
        if (conflict >= 0)
            qWarning("QMetaObject::indexOfSignal:%s: Conflict with %s::%s",
                      m->d.stringdata, m->d.superdata->d.stringdata, signal);
    }
#endif
    return i;
}

// 这里是所有基类的方法偏移量算法,就是累加基类所有的方法数目
int QMetaObject::methodOffset() const
{
    int offset = 0;
    const QMetaObject *m = d.superdata;
    while (m) {
        offset += priv(m->d.data)->methodCount;
        m = m->d.superdata;
    }
    return offset;
}

// 得到方法的元数据
QMetaMethod QMetaObject::method(int index) const
{
    int i = index;
 // 要减去基类的偏移
    i -= methodOffset();
 // 如果本类找不到,就到基类中去找
    if (i < 0 && d.superdata)
        return d.superdata->method(index);

 // 如果找到了,就填充QMetaMethod结构
    QMetaMethod result;
    if (i >= 0 && i < priv(d.data)->methodCount) {
  // 这里是类的元数据
        result.mobj = this;
  // 这里是方法相关数据在data数组中的偏移量
        result.handle = priv(d.data)->methodData + 5*i;
    }
    return result;
}

bool QMetaObject::connect(const QObject *sender, int signal_index,
                          const QObject *receiver, int method_index, int type, int *types)
{
 // 得到全局的连接列表
    QConnectionList *list = ::connectionList();
    if (!list)
        return false;
    QWriteLocker locker(&list->lock);
 // 增加一个连接
    list->addConnection(const_cast<QObject *>(sender), signal_index,
                        const_cast<QObject *>(receiver), method_index, type, types);
    return true;
}

void QConnectionList::addConnection(QObject *sender, int signal,
                                    QObject *receiver, int method,
                                    int type, int *types)
{
 // 构造一个连接
    QConnection c = { sender, signal, receiver, method, 0, 0, types };
    c.type = type; // don't warn on VC++6
    int at = -1;
 // 如果有中间被删除的连接,可以重用这个空间
    for (int i = 0; i < unusedConnections.size(); ++i) {
        if (!connections.at(unusedConnections.at(i)).inUse) {
            // reuse an unused connection
            at = unusedConnections.takeAt(i);
            connections[at] = c;
            break;
        }
    }
    if (at == -1) {
        // append new connection
        at = connections.size();
  // 加入一个连接
        connections << c;
    }
 // 构造sender,receiver连接的哈希表,加速搜索速度
    sendersHash.insert(sender, at);
    receiversHash.insert(receiver, at);
}

通过connect函数,我们建立了信号和槽的连接,并且把信号类+信号索引+槽类,槽索引作为记录写到了全局的connect列表中

一旦我们发送了信号,就应该调用相关槽中的方法了,这个过程其实就是查找全局的connect列表的过程,当然还要注意其中要对相关的参数打包和解包

// emit是发送信号的代码
void Foo::setValue(int v)
{
 if (v != val)
 {
  val = v;
  emit valueChanged(v);
 }
}

// 发送信号的真正实现在moc里面
// SIGNAL 0
void Foo::valueChanged(int _t1)
{
 // 首先把参数打包
    void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
 // 调用元数据类的激活
    QMetaObject::activate(this, &staticMetaObject, 0, _a);
}

void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
                           void **argv)
{
 // 增加一个基类偏移量
    int offset = m->methodOffset();
    activate(sender, offset + local_signal_index, offset + local_signal_index, argv);
}

void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv)
{
 // 这里得到的是QObject的数据,首先判断是否为阻塞设置
    if (sender->d_func()->blockSig)
        return;

 // 得到全局链表
    QConnectionList * const list = ::connectionList();
    if (!list)
        return;

    QReadLocker locker(&list->lock);

    void *empty_argv[] = { 0 };
    if (qt_signal_spy_callback_set.signal_begin_callback != 0) {
        locker.unlock();
        qt_signal_spy_callback_set.signal_begin_callback(sender, from_signal_index,
                                                         argv ? argv : empty_argv);
        locker.relock();
    }

 // 在sender的哈希表中得到sender的连接
    QConnectionList::Hash::const_iterator it = list->sendersHash.find(sender);
    const QConnectionList::Hash::const_iterator end = list->sendersHash.constEnd();

    if (it == end) {
        if (qt_signal_spy_callback_set.signal_end_callback != 0) {
            locker.unlock();
            qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index);
            locker.relock();
        }
        return;
    }

    QThread * const currentThread = QThread::currentThread();
    const int currentQThreadId = currentThread ? QThreadData::get(currentThread)->id : -1;

 // 记录sender连接的索引
    QVarLengthArray<int> connections;
    for (; it != end && it.key() == sender; ++it) {
        connections.append(it.value());
  // 打上使用标记,因为可能是放在队列中
        list->connections[it.value()].inUse = 1;
    }

    for (int i = 0; i < connections.size(); ++i) {
        const int at = connections.constData()[connections.size() - (i + 1)];
        QConnectionList * const list = ::connectionList();
  // 得到连接
        QConnection &c = list->connections[at];
        c.inUse = 0;
        if (!c.receiver || (c.signal < from_signal_index || c.signal > to_signal_index))
            continue;

  // 判断是否放到队列中
        // determine if this connection should be sent immediately or
        // put into the event queue
        if ((c.type == Qt::AutoConnection
             && (currentQThreadId != sender->d_func()->thread
                 || c.receiver->d_func()->thread != sender->d_func()->thread))
            || (c.type == Qt::QueuedConnection)) {
            ::queued_activate(sender, c, argv);
            continue;
        }

  // 为receiver设置当前发送者
        const int method = c.method;
        QObject * const previousSender = c.receiver->d_func()->currentSender;
        c.receiver->d_func()->currentSender = sender;
        list->lock.unlock();

        if (qt_signal_spy_callback_set.slot_begin_callback != 0)
            qt_signal_spy_callback_set.slot_begin_callback(c.receiver, method, argv ? argv : empty_argv);

#if defined(QT_NO_EXCEPTIONS)
        c.receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
#else
        try {
   // 调用receiver的方法
            c.receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
        } catch (...) {
            list->lock.lockForRead();
            if (c.receiver)
                c.receiver->d_func()->currentSender = previousSender;
            throw;
        }
#endif

        if (qt_signal_spy_callback_set.slot_end_callback != 0)
            qt_signal_spy_callback_set.slot_end_callback(c.receiver, method);

        list->lock.lockForRead();
        if (c.receiver)
            c.receiver->d_func()->currentSender = previousSender;
    }

    if (qt_signal_spy_callback_set.signal_end_callback != 0) {
        locker.unlock();
        qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index);
        locker.relock();
    }
}

// 响应信号也是在moc里实现的
int Foo::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
 // 首先在基类中调用方法,返回的id已经变成当前类的方法id了
    _id = QObject::qt_metacall(_c, _id, _a);
    if (_id < 0)
        return _id;
    if (_c == QMetaObject::InvokeMetaMethod) {
        switch (_id) {
  // 这里就是真正的调用方法了,注意参数的解包用法
        case 0: valueChanged(*reinterpret_cast< int(*)>(_a[1])); break;
        case 1: setValue(*reinterpret_cast< int(*)>(_a[1])); break;
        }
        _id -= 2;
    }
    return _id;
}
 转自:http://blog.csdn.net/oowgsoo/article/details/1529411

http://bbs.chinaunix.net/thread-1592226-1-1.html

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!