sigslot.h 61.3 KB
Newer Older
schultezub's avatar
schultezub committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*
 
 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/)
 
 1. #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.

 2. 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/
 
*/
schultezub's avatar
schultezub committed
89

schultezub's avatar
schultezub committed
90
91
#ifndef SIGSLOT_H
#define SIGSLOT_H
schultezub's avatar
schultezub committed
92

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

#ifdef CAMPVIS_DYNAMIC_LIBS
    #ifdef SIGSLOT_BUILD_DLL
        // building library -> export symbols
        #ifdef WIN32
            #define SIGSLOT_API __declspec(dllexport)
        #else
            #define SIGSLOT_API
        #endif
    #else
        // including library -> import symbols
        #ifdef WIN32
            #define SIGSLOT_API __declspec(dllimport)
        #else
            #define SIGSLOT_API
        #endif
    #endif
#else
    // building/including static library -> do nothing
    #define SIGSLOT_API
#endif


schultezub's avatar
schultezub committed
116
117
#include <set>
#include <list>
118
119
120

#include <tbb/compat/condition_variable>
#include <tbb/concurrent_queue.h>
121
#include <tbb/spin_rw_mutex.h>
schultezub's avatar
schultezub committed
122

123
124
125
#include "ext/tgt/runnable.h"
#include "ext/tgt/singleton.h"

schultezub's avatar
schultezub committed
126
127
128
129
130
131
132
133
134
135
#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 {

136
    /// Base class for signal handles that provides an interface to emit the signal.
137
138
    class _signal_handle_base {
    public:
139
        /// Virtual destructor
140
        virtual ~_signal_handle_base() {};
141
        /// Emits the signal of this signal handle.
142
143
144
        virtual void emitSignal() const = 0;
    };

145
146
// ================================================================================================

147
148
149
150
151
152
153
154
155
156
157
158
159
    /**
     * Singleton class that takes care of queuing and asynchronously dispatching signals.
     * 
     * The signal_manager implements the Runnable interface, i.e. runs in it's own thread once it
     * was launched. The signal_manager takes care of dispatching signals to their connections.
     * This is either done synchrnously by using triggerSignal() or asynchronously by using 
     * queueSignal(). Furthermore it allows to check, whether the current thread is the 
     * signal_manager thread. This allows the default signal emitting method operator() to 
     * automatically decide on the dispatch type based on the emitting thread.
     * 
     * signal_manager can be considered as thread-safe.
     */
    class SIGSLOT_API signal_manager : public tgt::Singleton<signal_manager>, public tgt::Runnable {
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
        friend class tgt::Singleton<signal_manager>;

    public:
        /**
         * Directly dispatches the signal \a signal to all currently registered listeners.
         * \note    For using threaded signal dispatching use queueSignal()
         * \param   signal   signal to dispatch
         */
        void triggerSignal(_signal_handle_base* signal) const;

        /**
         * Enqueue \a signal into the list of signals to be dispatched.
         * \note    Dispatch will be perfomed in signal_mananger thread. For direct dispatch in
         *          caller thread use triggerSignal().
         * \param   signal   signal to dispatch
         * \return  True, if \a signal was successfully enqueued to signal queue.
         */
        bool queueSignal(_signal_handle_base* signal);

179
180
181
182
183
184
        /**
         * Checks whether calling thread is signal_manager thread.
         * \return  std::this_thread::get_id() == _this_thread_id
         */
        bool isCurrentThreadSignalManagerThread() const;

185
186
187
188
189
190
191
192
193
194
195
        /// \see Runnable:run
        virtual void run();
        /// \see Runnable:stop
        virtual void stop();

    private:
        /// Private constructor only for singleton
        signal_manager();
        /// Private destructor only for singleton
        ~signal_manager();

196
        /// Typedef for the signal queue
197
198
199
200
201
202
203
        typedef tbb::concurrent_queue<_signal_handle_base*> SignalQueue;

        SignalQueue _signalQueue;   ///< Queue for signals to be dispatched

        std::condition_variable _evaluationCondition; ///< conditional wait to be used when there are currently no jobs to process
        tbb::mutex _ecMutex; ///< Mutex for protecting _evaluationCondition

204
205
        std::thread::id _this_thread_id;

206
207
208
        static const std::string loggerCat_;
    };

209
210
// ================================================================================================

211
    typedef tbb::spin_rw_mutex tbb_mutex;
schultezub's avatar
schultezub committed
212
213
214
215
216
217
218

    // The multi threading policies only get compiled in if they are enabled.
    class multi_threaded_global
    {
    public:
        multi_threaded_global()
        {
219
            ;
schultezub's avatar
schultezub committed
220
221
222
223
224
225
226
227
228
229
230
231
        }

        multi_threaded_global(const multi_threaded_global&)
        {
            ;
        }

        virtual ~multi_threaded_global()
        {
            ;
        }

232
        tbb_mutex& get_mutex()
schultezub's avatar
schultezub committed
233
        {
234
235
            static tbb_mutex g_mutex;
            return g_mutex;
schultezub's avatar
schultezub committed
236
237
238
239
240
241
242
243
        }
    };

    class multi_threaded_local
    {
    public:
        multi_threaded_local()
        {
244
            ;
schultezub's avatar
schultezub committed
245
246
247
248
249
250
251
        }

        multi_threaded_local(const multi_threaded_local&)
        {
            ;
        }

252
        virtual ~multi_threaded_local()
schultezub's avatar
schultezub committed
253
254
255
256
        {
            ;
        }

257
        tbb_mutex& get_mutex() { return m_mutex; }
schultezub's avatar
schultezub committed
258
259

    private:
260
        tbb_mutex m_mutex;
schultezub's avatar
schultezub committed
261
    };
262
263
264
    
    template<class mt_policy>
    class lock_block_write : tbb_mutex::scoped_lock
schultezub's avatar
schultezub committed
265
266
    {
    public:
267
        lock_block_write(mt_policy *mtx) : tbb_mutex::scoped_lock(mtx->get_mutex(), true)
schultezub's avatar
schultezub committed
268
269
        {
        }
270
271
        
        ~lock_block_write()
schultezub's avatar
schultezub committed
272
273
274
275
        {
        }
    };

276
277
    template<class mt_policy>
    class lock_block_read : tbb_mutex::scoped_lock
schultezub's avatar
schultezub committed
278
279
    {
    public:
280
        lock_block_read(mt_policy *mtx) : tbb_mutex::scoped_lock(mtx->get_mutex(), false)
schultezub's avatar
schultezub committed
281
282
283
        {
        }

284
        ~lock_block_read()
schultezub's avatar
schultezub committed
285
286
287
288
        {
        }
    };

289
// ================================================================================================
290

schultezub's avatar
schultezub committed
291
292
    template<class mt_policy>
    class has_slots;
schultezub's avatar
schultezub committed
293
    
schultezub's avatar
schultezub committed
294
295
296
297
    template<class mt_policy>
    class _connection_base0
    {
    public:
schultezub's avatar
schultezub committed
298
        virtual ~_connection_base0() {}
schultezub's avatar
schultezub committed
299
300
301
302
303
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emitSignal() = 0;
        virtual _connection_base0* clone() = 0;
        virtual _connection_base0* duplicate(has_slots<mt_policy>* pnewdest) = 0;
    };
schultezub's avatar
schultezub committed
304
    
schultezub's avatar
schultezub committed
305
306
307
308
    template<class arg1_type, class mt_policy>
    class _connection_base1
    {
    public:
schultezub's avatar
schultezub committed
309
        virtual ~_connection_base1() {}
schultezub's avatar
schultezub committed
310
311
312
313
314
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emitSignal(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;
    };
schultezub's avatar
schultezub committed
315
    
schultezub's avatar
schultezub committed
316
317
318
319
    template<class arg1_type, class arg2_type, class mt_policy>
    class _connection_base2
    {
    public:
schultezub's avatar
schultezub committed
320
        virtual ~_connection_base2() {}
schultezub's avatar
schultezub committed
321
322
323
324
325
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emitSignal(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;
    };
schultezub's avatar
schultezub committed
326
    
schultezub's avatar
schultezub committed
327
328
329
330
    template<class arg1_type, class arg2_type, class arg3_type, class mt_policy>
    class _connection_base3
    {
    public:
schultezub's avatar
schultezub committed
331
        virtual ~_connection_base3() {}
schultezub's avatar
schultezub committed
332
333
334
335
336
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emitSignal(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;
    };
schultezub's avatar
schultezub committed
337
    
schultezub's avatar
schultezub committed
338
339
340
341
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy>
    class _connection_base4
    {
    public:
schultezub's avatar
schultezub committed
342
        virtual ~_connection_base4() {}
schultezub's avatar
schultezub committed
343
344
345
346
347
        virtual has_slots<mt_policy>* getdest() const = 0;
        virtual void emitSignal(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;
    };
schultezub's avatar
schultezub committed
348
    
schultezub's avatar
schultezub committed
349
350
351
352
353
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type,
    class arg5_type, class mt_policy>
    class _connection_base5
    {
    public:
schultezub's avatar
schultezub committed
354
        virtual ~_connection_base5() {}
schultezub's avatar
schultezub committed
355
        virtual has_slots<mt_policy>* getdest() const = 0;
356
357
358
        virtual void emitSignal(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;
schultezub's avatar
schultezub committed
359
    };
schultezub's avatar
schultezub committed
360
    
361
// ================================================================================================
schultezub's avatar
schultezub committed
362
    
schultezub's avatar
schultezub committed
363
364
365
366
367
    template<class mt_policy>
    class _signal_base : public mt_policy
    {
    public:
        virtual void slot_disconnect(has_slots<mt_policy>* pslot) = 0;
schultezub's avatar
schultezub committed
368
        virtual void slot_duplicate(has_slots<mt_policy> const* poldslot, has_slots<mt_policy>* pnewslot) = 0;
schultezub's avatar
schultezub committed
369
    };
schultezub's avatar
schultezub committed
370
    
schultezub's avatar
schultezub committed
371
372
373
374
    template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
    class has_slots : public mt_policy 
    {
    private:
schultezub's avatar
schultezub committed
375
        typedef typename std::set<_signal_base<mt_policy> *> sender_set;
schultezub's avatar
schultezub committed
376
        typedef typename sender_set::const_iterator const_iterator;
schultezub's avatar
schultezub committed
377
        
schultezub's avatar
schultezub committed
378
    public:
schultezub's avatar
schultezub committed
379
380
381
        has_slots() {}
        
        has_slots(has_slots const& hs) : mt_policy(hs)
schultezub's avatar
schultezub committed
382
        {
383
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
384
385
            const_iterator it = hs.m_senders.begin();
            const_iterator itEnd = hs.m_senders.end();
schultezub's avatar
schultezub committed
386
387
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
388
389
390
391
392
                (*it)->slot_duplicate(&hs, this);
                m_senders.insert(*it);
                ++it;
            }
        } 
schultezub's avatar
schultezub committed
393
        
schultezub's avatar
schultezub committed
394
395
        void signal_connect(_signal_base<mt_policy>* sender)
        {
396
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
397
398
            m_senders.insert(sender);
        }
schultezub's avatar
schultezub committed
399
        
schultezub's avatar
schultezub committed
400
401
        void signal_disconnect(_signal_base<mt_policy>* sender)
        {
402
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
403
404
            m_senders.erase(sender);
        }
schultezub's avatar
schultezub committed
405
        
schultezub's avatar
schultezub committed
406
407
408
409
        virtual ~has_slots()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
410
        
schultezub's avatar
schultezub committed
411
412
        void disconnect_all()
        {
413
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
414
415
            const_iterator it = m_senders.begin();
            const_iterator itEnd = m_senders.end();
schultezub's avatar
schultezub committed
416
417
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
418
419
420
                (*it)->slot_disconnect(this);
                ++it;
            }
schultezub's avatar
schultezub committed
421
            
schultezub's avatar
schultezub committed
422
423
            m_senders.erase(m_senders.begin(), m_senders.end());
        }
schultezub's avatar
schultezub committed
424
        
schultezub's avatar
schultezub committed
425
426
427
    private:
        sender_set m_senders;
    };
schultezub's avatar
schultezub committed
428
    
schultezub's avatar
schultezub committed
429
430
431
432
433
    template<class mt_policy>
    class _signal_base0 : public _signal_base<mt_policy>
    {
    public:
        typedef std::list<_connection_base0<mt_policy> *>  connections_list;
schultezub's avatar
schultezub committed
434
435
436
437
        
        _signal_base0() {}
        
        _signal_base0(_signal_base0 const& s) : _signal_base<mt_policy>(s)
schultezub's avatar
schultezub committed
438
        {
439
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
440
441
442
443
            typename connections_list::const_iterator it = s.m_connected_slots.begin();
            typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
444
445
446
447
448
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
                ++it;
            }
        }
schultezub's avatar
schultezub committed
449
        
schultezub's avatar
schultezub committed
450
451
452
453
        ~_signal_base0()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
454
        
schultezub's avatar
schultezub committed
455
456
        void disconnect_all()
        {
457
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
458
459
460
461
            typename connections_list::const_iterator it = m_connected_slots.begin();
            typename connections_list::const_iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
462
463
464
465
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
                ++it;
            }
schultezub's avatar
schultezub committed
466
            
schultezub's avatar
schultezub committed
467
468
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
469
        
schultezub's avatar
schultezub committed
470
471
        void disconnect(has_slots<mt_policy>* pclass)
        {
472
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
473
474
475
476
477
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                if ((*it)->getdest() == pclass) {
schultezub's avatar
schultezub committed
478
479
480
481
482
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }
schultezub's avatar
schultezub committed
483
                
schultezub's avatar
schultezub committed
484
485
486
                ++it;
            }
        }
schultezub's avatar
schultezub committed
487
        
schultezub's avatar
schultezub committed
488
489
        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
490
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
491
492
493
494
495
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                typename connections_list::iterator itNext = it;
schultezub's avatar
schultezub committed
496
                ++itNext;
schultezub's avatar
schultezub committed
497
498
                
                if ((*it)->getdest() == pslot) {
schultezub's avatar
schultezub committed
499
                    m_connected_slots.erase(it);
schultezub's avatar
schultezub committed
500
                    //          delete *it;
schultezub's avatar
schultezub committed
501
                }
schultezub's avatar
schultezub committed
502
                
schultezub's avatar
schultezub committed
503
504
505
                it = itNext;
            }
        }
schultezub's avatar
schultezub committed
506
507
        
        void slot_duplicate(has_slots<mt_policy> const* oldtarget, has_slots<mt_policy>* newtarget)
schultezub's avatar
schultezub committed
508
        {
509
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
510
511
512
513
514
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
515
516
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
517
                
schultezub's avatar
schultezub committed
518
519
520
                ++it;
            }
        }
521
522
523
524
525

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
526
        
schultezub's avatar
schultezub committed
527
528
529
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
530
    
schultezub's avatar
schultezub committed
531
532
533
534
535
    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;
schultezub's avatar
schultezub committed
536
537
538
539
        
        _signal_base1() {}
        
        _signal_base1(_signal_base1<arg1_type, mt_policy> const& s) : _signal_base<mt_policy>(s)
schultezub's avatar
schultezub committed
540
        {
541
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
542
543
544
545
            typename connections_list::const_iterator it = s.m_connected_slots.begin();
            typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
546
547
548
549
550
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
                ++it;
            }
        }
schultezub's avatar
schultezub committed
551
552
        
        void slot_duplicate(has_slots<mt_policy> const* oldtarget, has_slots<mt_policy>* newtarget)
schultezub's avatar
schultezub committed
553
        {
554
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
555
556
557
558
559
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
560
561
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
562
                
schultezub's avatar
schultezub committed
563
564
565
                ++it;
            }
        }
schultezub's avatar
schultezub committed
566
        
schultezub's avatar
schultezub committed
567
568
569
570
        ~_signal_base1()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
571
        
schultezub's avatar
schultezub committed
572
573
        void disconnect_all()
        {
574
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
575
576
577
578
            typename connections_list::const_iterator it = m_connected_slots.begin();
            typename connections_list::const_iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
579
580
581
582
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
                ++it;
            }
schultezub's avatar
schultezub committed
583
            
schultezub's avatar
schultezub committed
584
585
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
586
        
schultezub's avatar
schultezub committed
587
588
        void disconnect(has_slots<mt_policy>* pclass)
        {
589
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
590
591
592
593
594
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                if ((*it)->getdest() == pclass) {
schultezub's avatar
schultezub committed
595
596
597
598
599
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }
schultezub's avatar
schultezub committed
600
                
schultezub's avatar
schultezub committed
601
602
603
                ++it;
            }
        }
schultezub's avatar
schultezub committed
604
        
schultezub's avatar
schultezub committed
605
606
        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
607
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
608
609
610
611
612
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                typename connections_list::iterator itNext = it;
schultezub's avatar
schultezub committed
613
                ++itNext;
schultezub's avatar
schultezub committed
614
615
                
                if ((*it)->getdest() == pslot) {
schultezub's avatar
schultezub committed
616
                    m_connected_slots.erase(it);
schultezub's avatar
schultezub committed
617
                    //          delete *it;
schultezub's avatar
schultezub committed
618
                }
schultezub's avatar
schultezub committed
619
                
schultezub's avatar
schultezub committed
620
621
622
                it = itNext;
            }
        }
623
624
625
626
627

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
628
629
        
        
schultezub's avatar
schultezub committed
630
631
632
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
633
    
schultezub's avatar
schultezub committed
634
635
636
637
638
    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> *>
schultezub's avatar
schultezub committed
639
640
641
642
643
        connections_list;
        
        _signal_base2() {}
        
        _signal_base2(_signal_base2<arg1_type, arg2_type, mt_policy> const& s) : _signal_base<mt_policy>(s)
schultezub's avatar
schultezub committed
644
        {
645
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
646
647
648
649
            typename connections_list::const_iterator it = s.m_connected_slots.begin();
            typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
650
651
652
653
654
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
                ++it;
            }
        }
schultezub's avatar
schultezub committed
655
656
        
        void slot_duplicate(has_slots<mt_policy> const* oldtarget, has_slots<mt_policy>* newtarget)
schultezub's avatar
schultezub committed
657
        {
658
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
659
660
661
662
663
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
664
665
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
666
                
schultezub's avatar
schultezub committed
667
668
669
                ++it;
            }
        }
schultezub's avatar
schultezub committed
670
        
schultezub's avatar
schultezub committed
671
672
673
674
        ~_signal_base2()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
675
        
schultezub's avatar
schultezub committed
676
677
        void disconnect_all()
        {
678
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
679
680
681
682
            typename connections_list::const_iterator it = m_connected_slots.begin();
            typename connections_list::const_iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
683
684
685
686
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
                ++it;
            }
schultezub's avatar
schultezub committed
687
            
schultezub's avatar
schultezub committed
688
689
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
690
        
schultezub's avatar
schultezub committed
691
692
        void disconnect(has_slots<mt_policy>* pclass)
        {
693
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
694
695
696
697
698
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                if ((*it)->getdest() == pclass) {
schultezub's avatar
schultezub committed
699
700
701
702
703
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }
schultezub's avatar
schultezub committed
704
                
schultezub's avatar
schultezub committed
705
706
707
                ++it;
            }
        }
schultezub's avatar
schultezub committed
708
        
schultezub's avatar
schultezub committed
709
710
        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
711
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
712
713
714
715
716
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                typename connections_list::iterator itNext = it;
schultezub's avatar
schultezub committed
717
                ++itNext;
schultezub's avatar
schultezub committed
718
719
                
                if ((*it)->getdest() == pslot) {
schultezub's avatar
schultezub committed
720
                    m_connected_slots.erase(it);
schultezub's avatar
schultezub committed
721
                    //          delete *it;
schultezub's avatar
schultezub committed
722
                }
schultezub's avatar
schultezub committed
723
                
schultezub's avatar
schultezub committed
724
725
726
                it = itNext;
            }
        }
727
728
729
730
731

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
732
        
schultezub's avatar
schultezub committed
733
734
735
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
736
    
schultezub's avatar
schultezub committed
737
738
739
740
741
    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> *>
schultezub's avatar
schultezub committed
742
743
744
745
746
747
748
        connections_list;
        
        _signal_base3() {}
        
        _signal_base3(_signal_base3<arg1_type, arg2_type, arg3_type, mt_policy> const& s)
        : _signal_base<mt_policy>(s)
        {
749
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
750
751
752
753
            typename connections_list::const_iterator it = s.m_connected_slots.begin();
            typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
754
755
756
757
758
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
                ++it;
            }
        }
schultezub's avatar
schultezub committed
759
760
        
        void slot_duplicate(has_slots<mt_policy> const* oldtarget, has_slots<mt_policy>* newtarget)
schultezub's avatar
schultezub committed
761
        {
762
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
763
764
765
766
767
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
768
769
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
770
                
schultezub's avatar
schultezub committed
771
772
773
                ++it;
            }
        }
schultezub's avatar
schultezub committed
774
        
schultezub's avatar
schultezub committed
775
776
777
778
        ~_signal_base3()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
779
        
schultezub's avatar
schultezub committed
780
781
        void disconnect_all()
        {
782
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
783
784
785
786
            typename connections_list::const_iterator it = m_connected_slots.begin();
            typename connections_list::const_iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
787
788
789
790
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
                ++it;
            }
schultezub's avatar
schultezub committed
791
            
schultezub's avatar
schultezub committed
792
793
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
794
        
schultezub's avatar
schultezub committed
795
796
        void disconnect(has_slots<mt_policy>* pclass)
        {
797
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
798
799
800
801
802
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                if ((*it)->getdest() == pclass) {
schultezub's avatar
schultezub committed
803
804
805
806
807
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }
schultezub's avatar
schultezub committed
808
                
schultezub's avatar
schultezub committed
809
810
811
                ++it;
            }
        }
schultezub's avatar
schultezub committed
812
        
schultezub's avatar
schultezub committed
813
814
        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
815
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
816
817
818
819
820
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                typename connections_list::iterator itNext = it;
schultezub's avatar
schultezub committed
821
                ++itNext;
schultezub's avatar
schultezub committed
822
823
                
                if ((*it)->getdest() == pslot) {
schultezub's avatar
schultezub committed
824
                    m_connected_slots.erase(it);
schultezub's avatar
schultezub committed
825
                    //          delete *it;
schultezub's avatar
schultezub committed
826
                }
schultezub's avatar
schultezub committed
827
                
schultezub's avatar
schultezub committed
828
829
830
                it = itNext;
            }
        }
831
832
833
834
835

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
836
        
schultezub's avatar
schultezub committed
837
838
839
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
840
    
schultezub's avatar
schultezub committed
841
842
843
844
845
    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,
schultezub's avatar
schultezub committed
846
847
848
849
        arg4_type, mt_policy> *>  connections_list;
        
        _signal_base4() {}
        
schultezub's avatar
schultezub committed
850
        _signal_base4(const _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s)
schultezub's avatar
schultezub committed
851
        : _signal_base<mt_policy>(s)
schultezub's avatar
schultezub committed
852
        {
853
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
854
855
856
857
            typename connections_list::const_iterator it = s.m_connected_slots.begin();
            typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
858
859
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
schultezub's avatar
schultezub committed
860
                
schultezub's avatar
schultezub committed
861
862
863
                ++it;
            }
        }
schultezub's avatar
schultezub committed
864
        
schultezub's avatar
schultezub committed
865
866
        void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
        {
867
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
868
869
870
871
872
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
873
874
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
875
                
schultezub's avatar
schultezub committed
876
877
878
                ++it;
            }
        }
schultezub's avatar
schultezub committed
879
        
schultezub's avatar
schultezub committed
880
881
882
883
        ~_signal_base4()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
884
        
schultezub's avatar
schultezub committed
885
886
        void disconnect_all()
        {
887
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
888
889
890
891
            typename connections_list::const_iterator it = m_connected_slots.begin();
            typename connections_list::const_iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
892
893
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
schultezub's avatar
schultezub committed
894
                
schultezub's avatar
schultezub committed
895
896
                ++it;
            }
schultezub's avatar
schultezub committed
897
            
schultezub's avatar
schultezub committed
898
899
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
900
        
schultezub's avatar
schultezub committed
901
902
        void disconnect(has_slots<mt_policy>* pclass)
        {
903
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
904
905
906
907
908
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                if ((*it)->getdest() == pclass) {
schultezub's avatar
schultezub committed
909
910
911
912
913
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }
schultezub's avatar
schultezub committed
914
                
schultezub's avatar
schultezub committed
915
916
917
                ++it;
            }
        }
schultezub's avatar
schultezub committed
918
        
schultezub's avatar
schultezub committed
919
920
        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
921
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
922
923
924
925
926
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                typename connections_list::iterator itNext = it;
schultezub's avatar
schultezub committed
927
                ++itNext;
schultezub's avatar
schultezub committed
928
929
                
                if ((*it)->getdest() == pslot) {
schultezub's avatar
schultezub committed
930
                    m_connected_slots.erase(it);
schultezub's avatar
schultezub committed
931
                    //          delete *it;
schultezub's avatar
schultezub committed
932
                }
schultezub's avatar
schultezub committed
933
                
schultezub's avatar
schultezub committed
934
935
936
                it = itNext;
            }
        }
937
938
939
940
941

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
942
        
schultezub's avatar
schultezub committed
943
944
945
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
946
    
947
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class arg5_type, class mt_policy>
schultezub's avatar
schultezub committed
948
949
950
    class _signal_base5 : public _signal_base<mt_policy>
    {
    public:
951
        typedef std::list<_connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, mt_policy> *>  connections_list;
schultezub's avatar
schultezub committed
952
953
954
        
        _signal_base5() {}
        
955
        _signal_base5(const _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, mt_policy>& s)
schultezub's avatar
schultezub committed
956
        : _signal_base<mt_policy>(s)
schultezub's avatar
schultezub committed
957
        {
958
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
959
960
961
962
            typename connections_list::const_iterator it = s.m_connected_slots.begin();
            typename connections_list::const_iterator itEnd = s.m_connected_slots.end();
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
963
964
                (*it)->getdest()->signal_connect(this);
                m_connected_slots.push_back((*it)->clone());
schultezub's avatar
schultezub committed
965
                
schultezub's avatar
schultezub committed
966
967
968
                ++it;
            }
        }
schultezub's avatar
schultezub committed
969
        
schultezub's avatar
schultezub committed
970
971
        void slot_duplicate(const has_slots<mt_policy>* oldtarget, has_slots<mt_policy>* newtarget)
        {
972
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
973
974
975
976
977
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                if ((*it)->getdest() == oldtarget) {
schultezub's avatar
schultezub committed
978
979
                    m_connected_slots.push_back((*it)->duplicate(newtarget));
                }
schultezub's avatar
schultezub committed
980
                
schultezub's avatar
schultezub committed
981
982
983
                ++it;
            }
        }
schultezub's avatar
schultezub committed
984
        
schultezub's avatar
schultezub committed
985
986
987
988
        ~_signal_base5()
        {
            disconnect_all();
        }
schultezub's avatar
schultezub committed
989
        
schultezub's avatar
schultezub committed
990
991
        void disconnect_all()
        {
992
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
993
994
995
996
            typename connections_list::const_iterator it = m_connected_slots.begin();
            typename connections_list::const_iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
schultezub's avatar
schultezub committed
997
998
                (*it)->getdest()->signal_disconnect(this);
                delete *it;
schultezub's avatar
schultezub committed
999
                
schultezub's avatar
schultezub committed
1000
1001
                ++it;
            }
schultezub's avatar
schultezub committed
1002
            
schultezub's avatar
schultezub committed
1003
1004
            m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());
        }
schultezub's avatar
schultezub committed
1005
        
schultezub's avatar
schultezub committed
1006
1007
        void disconnect(has_slots<mt_policy>* pclass)
        {
1008
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
1009
1010
1011
1012
1013
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                if ((*it)->getdest() == pclass) {
schultezub's avatar
schultezub committed
1014
1015
1016
1017
1018
                    delete *it;
                    m_connected_slots.erase(it);
                    pclass->signal_disconnect(this);
                    return;
                }
schultezub's avatar
schultezub committed
1019
                
schultezub's avatar
schultezub committed
1020
1021
1022
                ++it;
            }
        }
schultezub's avatar
schultezub committed
1023
        
schultezub's avatar
schultezub committed
1024
1025
        void slot_disconnect(has_slots<mt_policy>* pslot)
        {
1026
            lock_block_write<mt_policy> lock(this);
schultezub's avatar
schultezub committed
1027
1028
1029
1030
1031
            typename connections_list::iterator it = m_connected_slots.begin();
            typename connections_list::iterator itEnd = m_connected_slots.end();
            
            while (it != itEnd) {
                typename connections_list::iterator itNext = it;
schultezub's avatar
schultezub committed
1032
                ++itNext;
schultezub's avatar
schultezub committed
1033
1034
                
                if ((*it)->getdest() == pslot) {
schultezub's avatar
schultezub committed
1035
                    m_connected_slots.erase(it);
schultezub's avatar
schultezub committed
1036
                    //          delete *it;
schultezub's avatar
schultezub committed
1037
                }
schultezub's avatar
schultezub committed
1038
                
schultezub's avatar
schultezub committed
1039
1040
1041
                it = itNext;
            }
        }
1042
1043
1044
1045
1046

        bool has_connections() const
        {
            return !m_connected_slots.empty();
        }
schultezub's avatar
schultezub committed
1047
        
schultezub's avatar
schultezub committed
1048
1049
1050
    protected:
        connections_list m_connected_slots;   
    };
schultezub's avatar
schultezub committed
1051
    
1052
1053
1054
1055
// ================================================================================================

    template<class dest_type, class mt_policy>
    class _connection0 : public _connection_base0<mt_policy>
schultezub's avatar
schultezub committed
1056
1057
    {
    public:
1058
        _connection0()
schultezub's avatar
schultezub committed
1059
        {
1060
1061
            m_pobject = 0;
            m_pmemfun = 0;
schultezub's avatar
schultezub committed
1062
        }
schultezub's avatar
schultezub committed
1063
        
1064
        _connection0(dest_type* pobject, void (dest_type::*pmemfun)())
schultezub's avatar
schultezub committed
1065
        {
1066
1067
            m_pobject = pobject;
            m_pmemfun = pmemfun;
schultezub's avatar
schultezub committed
1068
        }
schultezub's avatar
schultezub committed
1069
        
1070
        virtual _connection_base0<mt_policy>* clone()
schultezub's avatar
schultezub committed
1071
        {
1072
            return new _connection0<dest_type, mt_policy>(*this);
schultezub's avatar
schultezub committed
1073
        }
schultezub's avatar
schultezub committed
1074
        
1075
        virtual _connection_base0<mt_policy>* duplicate(has_slots<mt_policy>* pnewdest)
schultezub's avatar
schultezub committed
1076
        {
1077
            return new _connection0<dest_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);
schultezub's avatar
schultezub committed
1078
        }
schultezub's avatar
schultezub committed
1079
        
1080
        virtual void emitSignal()
schultezub's avatar
schultezub committed
1081
        {
1082
            (m_pobject->*m_pmemfun)();
schultezub's avatar
schultezub committed
1083
        }
schultezub's avatar
schultezub committed
1084
        
1085
        virtual has_slots<mt_policy>* getdest() const
1086
        {
1087
            return m_pobject;
Christian Schulte zu Berge's avatar