Line data Source code
1 : /*
2 : Template for Signa1, Signal2, ... classes that support signals
3 : with 1, 2, ... parameters
4 :
5 : Begin: 2007-01-23
6 : */
7 : // Copyright Frank Mori Hess 2007-2008
8 : //
9 : // Use, modification and
10 : // distribution is subject to the Boost Software License, Version
11 : // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
12 : // http://www.boost.org/LICENSE_1_0.txt)
13 :
14 : // This file is included iteratively, and should not be protected from multiple inclusion
15 :
16 : #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
17 : #define BOOST_SIGNALS2_NUM_ARGS BOOST_PP_ITERATION()
18 : #else
19 : #define BOOST_SIGNALS2_NUM_ARGS 1
20 : #endif
21 :
22 : // R, T1, T2, ..., TN, Combiner, Group, GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex
23 : #define BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION \
24 : BOOST_SIGNALS2_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS), \
25 : Combiner, Group, GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex
26 :
27 : namespace boost
28 : {
29 : namespace signals2
30 : {
31 : namespace detail
32 : {
33 : // helper for bound_extended_slot_function that handles specialization for void return
34 : template<typename R>
35 : class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)
36 : {
37 : public:
38 : typedef R result_type;
39 : template<typename ExtendedSlotFunction BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
40 : BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
41 : result_type operator()(ExtendedSlotFunction &func, const connection &conn
42 : BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
43 : BOOST_SIGNALS2_FULL_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
44 : {
45 : return func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
46 : BOOST_SIGNALS2_FORWARDED_ARGS(BOOST_SIGNALS2_NUM_ARGS));
47 : }
48 : };
49 : #ifdef BOOST_NO_VOID_RETURNS
50 : template<>
51 : class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)<void>
52 : {
53 : public:
54 : typedef result_type_wrapper<void>::type result_type;
55 : template<typename ExtendedSlotFunction BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
56 : BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
57 : result_type operator()(ExtendedSlotFunction &func, const connection &conn
58 : BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
59 : BOOST_SIGNALS2_FULL_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
60 : {
61 : func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
62 : BOOST_SIGNALS2_FORWARDED_ARGS(BOOST_SIGNALS2_NUM_ARGS));
63 : return result_type();
64 : }
65 : };
66 : #endif
67 : // wrapper around an signalN::extended_slot_function which binds the
68 : // connection argument so it looks like a normal
69 : // signalN::slot_function
70 :
71 : template<typename ExtendedSlotFunction>
72 : class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)
73 : {
74 : public:
75 : typedef typename result_type_wrapper<typename ExtendedSlotFunction::result_type>::type result_type;
76 : BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)(const ExtendedSlotFunction &fun):
77 : _fun(fun), _connection(new connection)
78 : {}
79 : void set_connection(const connection &conn)
80 : {
81 : *_connection = conn;
82 : }
83 :
84 : #if BOOST_SIGNALS2_NUM_ARGS > 0
85 : template<BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
86 : #endif // BOOST_SIGNALS2_NUM_ARGS > 0
87 : result_type operator()(BOOST_SIGNALS2_FULL_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS))
88 : {
89 : return BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)
90 : <typename ExtendedSlotFunction::result_type>()
91 : (_fun, *_connection BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
92 : BOOST_SIGNALS2_FORWARDED_ARGS(BOOST_SIGNALS2_NUM_ARGS));
93 : }
94 : // const overload
95 : #if BOOST_SIGNALS2_NUM_ARGS > 0
96 : template<BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
97 : #endif // BOOST_SIGNALS2_NUM_ARGS > 0
98 : result_type operator()(BOOST_SIGNALS2_FULL_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
99 : {
100 : return BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)
101 : <typename ExtendedSlotFunction::result_type>()
102 : (_fun, *_connection BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
103 : BOOST_SIGNALS2_FORWARDED_ARGS(BOOST_SIGNALS2_NUM_ARGS));
104 : }
105 : template<typename T>
106 : bool contains(const T &other) const
107 : {
108 : return _fun.contains(other);
109 : }
110 : private:
111 : BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)()
112 : {}
113 :
114 : ExtendedSlotFunction _fun;
115 : boost::shared_ptr<connection> _connection;
116 : };
117 :
118 : template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
119 : class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
120 : template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
121 : class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
122 :
123 : template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
124 : class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION
125 : {
126 : public:
127 : typedef SlotFunction slot_function_type;
128 : // typedef slotN<Signature, SlotFunction> slot_type;
129 : typedef BOOST_SIGNALS2_SLOT_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
130 : <BOOST_SIGNALS2_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS),
131 : slot_function_type> slot_type;
132 : typedef ExtendedSlotFunction extended_slot_function_type;
133 : // typedef slotN+1<R, const connection &, T1, T2, ..., TN, extended_slot_function_type> extended_slot_type;
134 : typedef BOOST_SIGNALS2_EXTENDED_SLOT_TYPE(BOOST_SIGNALS2_NUM_ARGS) extended_slot_type;
135 : typedef typename nonvoid<typename slot_function_type::result_type>::type nonvoid_slot_result_type;
136 : private:
137 : #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
138 : class slot_invoker;
139 : #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
140 : typedef variadic_slot_invoker<nonvoid_slot_result_type, Args...> slot_invoker;
141 : #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
142 : typedef slot_call_iterator_cache<nonvoid_slot_result_type, slot_invoker> slot_call_iterator_cache_type;
143 : typedef typename group_key<Group>::type group_key_type;
144 : typedef shared_ptr<connection_body<group_key_type, slot_type, Mutex> > connection_body_type;
145 : typedef grouped_list<Group, GroupCompare, connection_body_type> connection_list_type;
146 : typedef BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)<extended_slot_function_type>
147 : bound_extended_slot_function_type;
148 : public:
149 : typedef Combiner combiner_type;
150 : typedef typename result_type_wrapper<typename combiner_type::result_type>::type result_type;
151 : typedef Group group_type;
152 : typedef GroupCompare group_compare_type;
153 : typedef typename detail::slot_call_iterator_t<slot_invoker,
154 : typename connection_list_type::iterator, connection_body<group_key_type, slot_type, Mutex> > slot_call_iterator;
155 : typedef detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
156 : <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> weak_signal_type;
157 :
158 179534 : BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg,
159 : const group_compare_type &group_compare):
160 89767 : _shared_state(boost::make_shared<invocation_state>(connection_list_type(group_compare), combiner_arg)),
161 89767 : _garbage_collector_it(_shared_state->connection_bodies().end()),
162 89767 : _mutex(new mutex_type())
163 179534 : {}
164 : // connect slot
165 29777 : connection connect(const slot_type &slot, connect_position position = at_back)
166 : {
167 29777 : garbage_collecting_lock<mutex_type> lock(*_mutex);
168 29777 : return nolock_connect(lock, slot, position);
169 29777 : }
170 : connection connect(const group_type &group,
171 : const slot_type &slot, connect_position position = at_back)
172 : {
173 : garbage_collecting_lock<mutex_type> lock(*_mutex);
174 : return nolock_connect(lock, group, slot, position);
175 : }
176 : // connect extended slot
177 : connection connect_extended(const extended_slot_type &ext_slot, connect_position position = at_back)
178 : {
179 : garbage_collecting_lock<mutex_type> lock(*_mutex);
180 : bound_extended_slot_function_type bound_slot(ext_slot.slot_function());
181 : slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot);
182 : connection conn = nolock_connect(lock, slot, position);
183 : bound_slot.set_connection(conn);
184 : return conn;
185 : }
186 : connection connect_extended(const group_type &group,
187 : const extended_slot_type &ext_slot, connect_position position = at_back)
188 : {
189 : garbage_collecting_lock<Mutex> lock(*_mutex);
190 : bound_extended_slot_function_type bound_slot(ext_slot.slot_function());
191 : slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot);
192 : connection conn = nolock_connect(lock, group, slot, position);
193 : bound_slot.set_connection(conn);
194 : return conn;
195 : }
196 : // disconnect slot(s)
197 : void disconnect_all_slots()
198 : {
199 : shared_ptr<invocation_state> local_state =
200 : get_readable_state();
201 : typename connection_list_type::iterator it;
202 : for(it = local_state->connection_bodies().begin();
203 : it != local_state->connection_bodies().end(); ++it)
204 : {
205 : (*it)->disconnect();
206 : }
207 : }
208 : void disconnect(const group_type &group)
209 : {
210 : shared_ptr<invocation_state> local_state =
211 : get_readable_state();
212 : group_key_type group_key(grouped_slots, group);
213 : typename connection_list_type::iterator it;
214 : typename connection_list_type::iterator end_it =
215 : local_state->connection_bodies().upper_bound(group_key);
216 : for(it = local_state->connection_bodies().lower_bound(group_key);
217 : it != end_it; ++it)
218 : {
219 : (*it)->disconnect();
220 : }
221 : }
222 : template <typename T>
223 : void disconnect(const T &slot)
224 : {
225 : typedef mpl::bool_<(is_convertible<T, group_type>::value)> is_group;
226 : do_disconnect(unwrap_ref(slot), is_group());
227 : }
228 : // emit signal
229 1044981 : result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
230 : {
231 1044981 : shared_ptr<invocation_state> local_state;
232 1044981 : typename connection_list_type::iterator it;
233 : {
234 1044981 : garbage_collecting_lock<mutex_type> list_lock(*_mutex);
235 : // only clean up if it is safe to do so
236 1044980 : if(_shared_state.unique())
237 1044980 : nolock_cleanup_connections(list_lock, false, 1);
238 : /* Make a local copy of _shared_state while holding mutex, so we are
239 : thread safe against the combiner or connection list getting modified
240 : during invocation. */
241 1044980 : local_state = _shared_state;
242 1044980 : }
243 1044980 : slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
244 1044981 : slot_call_iterator_cache_type cache(invoker);
245 1044979 : invocation_janitor janitor(cache, *this, &local_state->connection_bodies());
246 1044981 : return detail::combiner_invoker<typename combiner_type::result_type>()
247 : (
248 1044979 : local_state->combiner(),
249 1044981 : slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache),
250 1044981 : slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache)
251 : );
252 1044987 : }
253 : result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
254 : {
255 : shared_ptr<invocation_state> local_state;
256 : typename connection_list_type::iterator it;
257 : {
258 : garbage_collecting_lock<mutex_type> list_lock(*_mutex);
259 : // only clean up if it is safe to do so
260 : if(_shared_state.unique())
261 : nolock_cleanup_connections(list_lock, false, 1);
262 : /* Make a local copy of _shared_state while holding mutex, so we are
263 : thread safe against the combiner or connection list getting modified
264 : during invocation. */
265 : local_state = _shared_state;
266 : }
267 : slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
268 : slot_call_iterator_cache_type cache(invoker);
269 : invocation_janitor janitor(cache, *this, &local_state->connection_bodies());
270 : return detail::combiner_invoker<typename combiner_type::result_type>()
271 : (
272 : local_state->combiner(),
273 : slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache),
274 : slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache)
275 : );
276 : }
277 : std::size_t num_slots() const
278 : {
279 : shared_ptr<invocation_state> local_state =
280 : get_readable_state();
281 : typename connection_list_type::iterator it;
282 : std::size_t count = 0;
283 : for(it = local_state->connection_bodies().begin();
284 : it != local_state->connection_bodies().end(); ++it)
285 : {
286 : if((*it)->connected()) ++count;
287 : }
288 : return count;
289 : }
290 2371 : bool empty() const
291 : {
292 : shared_ptr<invocation_state> local_state =
293 2371 : get_readable_state();
294 2371 : typename connection_list_type::iterator it;
295 4742 : for(it = local_state->connection_bodies().begin();
296 2371 : it != local_state->connection_bodies().end(); ++it)
297 : {
298 0 : if((*it)->connected()) return false;
299 0 : }
300 2371 : return true;
301 2371 : }
302 : combiner_type combiner() const
303 : {
304 : unique_lock<mutex_type> lock(*_mutex);
305 : return _shared_state->combiner();
306 : }
307 : void set_combiner(const combiner_type &combiner_arg)
308 : {
309 : unique_lock<mutex_type> lock(*_mutex);
310 : if(_shared_state.unique())
311 : _shared_state->combiner() = combiner_arg;
312 : else
313 : _shared_state = boost::make_shared<invocation_state>(*_shared_state, combiner_arg);
314 : }
315 : private:
316 : typedef Mutex mutex_type;
317 :
318 : // slot_invoker is passed to slot_call_iterator_t to run slots
319 : #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
320 : class slot_invoker
321 : {
322 : public:
323 : typedef nonvoid_slot_result_type result_type;
324 : // typename add_reference<Tn>::type
325 : #define BOOST_SIGNALS2_ADD_REF_TYPE(z, n, data) \
326 : typename add_reference<BOOST_PP_CAT(T, BOOST_PP_INC(n))>::type
327 : // typename add_reference<Tn>::type argn
328 : #define BOOST_SIGNALS2_ADD_REF_ARG(z, n, data) \
329 : BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) \
330 : BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~)
331 : // typename add_reference<T1>::type arg1, typename add_reference<T2>::type arg2, ..., typename add_reference<Tn>::type argn
332 : #define BOOST_SIGNALS2_ADD_REF_ARGS(arity) \
333 : BOOST_PP_ENUM(arity, BOOST_SIGNALS2_ADD_REF_ARG, ~)
334 : slot_invoker(BOOST_SIGNALS2_ADD_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) BOOST_PP_EXPR_IF(BOOST_SIGNALS2_NUM_ARGS, :)
335 : #undef BOOST_SIGNALS2_ADD_REF_ARGS
336 :
337 : // m_argn
338 : #define BOOST_SIGNALS2_M_ARG_NAME(z, n, data) BOOST_PP_CAT(m_arg, BOOST_PP_INC(n))
339 : // m_argn ( argn )
340 : #define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \
341 : BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ( BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~) )
342 : // m_arg1(arg1), m_arg2(arg2), ..., m_argn(argn)
343 : BOOST_PP_ENUM(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~)
344 : #undef BOOST_SIGNALS2_MISC_STATEMENT
345 : {}
346 : result_type operator ()(const connection_body_type &connectionBody) const
347 : {
348 : return m_invoke<typename slot_type::result_type>(connectionBody);
349 : }
350 : private:
351 : // declare assignment operator private since this class might have reference or const members
352 : slot_invoker & operator=(const slot_invoker &);
353 :
354 : #define BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT(z, n, data) \
355 : BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ;
356 : BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT, ~)
357 : #undef BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT
358 : #undef BOOST_SIGNALS2_ADD_REF_ARG
359 : #undef BOOST_SIGNALS2_ADD_REF_TYPE
360 :
361 : // m_arg1, m_arg2, ..., m_argn
362 : #define BOOST_SIGNALS2_M_ARG_NAMES(arity) BOOST_PP_ENUM(arity, BOOST_SIGNALS2_M_ARG_NAME, ~)
363 : template<typename SlotResultType>
364 : result_type m_invoke(const connection_body_type &connectionBody,
365 : typename boost::enable_if<boost::is_void<SlotResultType> >::type * = 0) const
366 : {
367 : connectionBody->slot().slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
368 : return void_type();
369 : }
370 : template<typename SlotResultType>
371 : result_type m_invoke(const connection_body_type &connectionBody,
372 : typename boost::disable_if<boost::is_void<SlotResultType> >::type * = 0) const
373 : {
374 : return connectionBody->slot().slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
375 : }
376 : };
377 : #undef BOOST_SIGNALS2_M_ARG_NAMES
378 : #undef BOOST_SIGNALS2_M_ARG_NAME
379 :
380 : #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
381 : // a struct used to optimize (minimize) the number of shared_ptrs that need to be created
382 : // inside operator()
383 : class invocation_state
384 : {
385 : public:
386 179534 : invocation_state(const connection_list_type &connections_in,
387 89767 : const combiner_type &combiner_in): _connection_bodies(new connection_list_type(connections_in)),
388 89767 : _combiner(new combiner_type(combiner_in))
389 179534 : {}
390 0 : invocation_state(const invocation_state &other, const connection_list_type &connections_in):
391 0 : _connection_bodies(new connection_list_type(connections_in)),
392 0 : _combiner(other._combiner)
393 0 : {}
394 : invocation_state(const invocation_state &other, const combiner_type &combiner_in):
395 : _connection_bodies(other._connection_bodies),
396 : _combiner(new combiner_type(combiner_in))
397 : {}
398 8875755 : connection_list_type & connection_bodies() { return *_connection_bodies; }
399 : const connection_list_type & connection_bodies() const { return *_connection_bodies; }
400 1044981 : combiner_type & combiner() { return *_combiner; }
401 : const combiner_type & combiner() const { return *_combiner; }
402 : private:
403 : invocation_state(const invocation_state &);
404 :
405 : shared_ptr<connection_list_type> _connection_bodies;
406 : shared_ptr<combiner_type> _combiner;
407 : };
408 : // Destructor of invocation_janitor does some cleanup when a signal invocation completes.
409 : // Code can't be put directly in signal's operator() due to complications from void return types.
410 : class invocation_janitor: noncopyable
411 : {
412 : public:
413 : typedef BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) signal_type;
414 2089962 : invocation_janitor
415 : (
416 : const slot_call_iterator_cache_type &cache,
417 : const signal_type &sig,
418 : const connection_list_type *connection_bodies
419 1044981 : ):_cache(cache), _sig(sig), _connection_bodies(connection_bodies)
420 2089962 : {}
421 2089960 : ~invocation_janitor()
422 1044980 : {
423 : // force a full cleanup of disconnected slots if there are too many
424 1044980 : if(_cache.disconnected_slot_count > _cache.connected_slot_count)
425 : {
426 0 : _sig.force_cleanup_connections(_connection_bodies);
427 0 : }
428 2089960 : }
429 : private:
430 : const slot_call_iterator_cache_type &_cache;
431 : const signal_type &_sig;
432 : const connection_list_type *_connection_bodies;
433 : };
434 :
435 : // clean up disconnected connections
436 1074758 : void nolock_cleanup_connections_from(garbage_collecting_lock<mutex_type> &lock,
437 : bool grab_tracked,
438 : const typename connection_list_type::iterator &begin, unsigned count = 0) const
439 : {
440 1074758 : BOOST_ASSERT(_shared_state.unique());
441 1074758 : typename connection_list_type::iterator it;
442 : unsigned i;
443 2804940 : for(it = begin, i = 0;
444 1402470 : it != _shared_state->connection_bodies().end() && (count == 0 || i < count);
445 327712 : ++i)
446 : {
447 : bool connected;
448 327712 : if(grab_tracked)
449 5415 : (*it)->disconnect_expired_slot(lock);
450 327712 : connected = (*it)->nolock_nograb_connected();
451 327712 : if(connected == false)
452 : {
453 1066 : it = _shared_state->connection_bodies().erase((*it)->group_key(), it);
454 1066 : }else
455 : {
456 326646 : ++it;
457 : }
458 327712 : }
459 1074758 : _garbage_collector_it = it;
460 1074758 : }
461 : // clean up a few connections in constant time
462 1074758 : void nolock_cleanup_connections(garbage_collecting_lock<mutex_type> &lock,
463 : bool grab_tracked, unsigned count) const
464 : {
465 1074758 : BOOST_ASSERT(_shared_state.unique());
466 1074758 : typename connection_list_type::iterator begin;
467 1074758 : if(_garbage_collector_it == _shared_state->connection_bodies().end())
468 : {
469 1048274 : begin = _shared_state->connection_bodies().begin();
470 1048274 : }else
471 : {
472 26484 : begin = _garbage_collector_it;
473 : }
474 1074758 : nolock_cleanup_connections_from(lock, grab_tracked, begin, count);
475 1074758 : }
476 : /* Make a new copy of the slot list if it is currently being read somewhere else
477 : */
478 29777 : void nolock_force_unique_connection_list(garbage_collecting_lock<mutex_type> &lock)
479 : {
480 29777 : if(_shared_state.unique() == false)
481 : {
482 0 : _shared_state = boost::make_shared<invocation_state>(*_shared_state, _shared_state->connection_bodies());
483 0 : nolock_cleanup_connections_from(lock, true, _shared_state->connection_bodies().begin());
484 0 : }else
485 : {
486 : /* We need to try and check more than just 1 connection here to avoid corner
487 : cases where certain repeated connect/disconnect patterns cause the slot
488 : list to grow without limit. */
489 29777 : nolock_cleanup_connections(lock, true, 2);
490 : }
491 29777 : }
492 : // force a full cleanup of the connection list
493 0 : void force_cleanup_connections(const connection_list_type *connection_bodies) const
494 : {
495 0 : garbage_collecting_lock<mutex_type> list_lock(*_mutex);
496 : // if the connection list passed in as a parameter is no longer in use,
497 : // we don't need to do any cleanup.
498 0 : if(&_shared_state->connection_bodies() != connection_bodies)
499 : {
500 0 : return;
501 : }
502 0 : if(_shared_state.unique() == false)
503 : {
504 0 : _shared_state = boost::make_shared<invocation_state>(*_shared_state, _shared_state->connection_bodies());
505 0 : }
506 0 : nolock_cleanup_connections_from(list_lock, false, _shared_state->connection_bodies().begin());
507 0 : }
508 2371 : shared_ptr<invocation_state> get_readable_state() const
509 : {
510 2371 : unique_lock<mutex_type> list_lock(*_mutex);
511 2371 : return _shared_state;
512 2371 : }
513 29777 : connection_body_type create_new_connection(garbage_collecting_lock<mutex_type> &lock,
514 : const slot_type &slot)
515 : {
516 29777 : nolock_force_unique_connection_list(lock);
517 29777 : return boost::make_shared<connection_body<group_key_type, slot_type, Mutex> >(slot, _mutex);
518 : }
519 : void do_disconnect(const group_type &group, mpl::bool_<true> /* is_group */)
520 : {
521 : disconnect(group);
522 : }
523 : template<typename T>
524 : void do_disconnect(const T &slot, mpl::bool_<false> /* is_group */)
525 : {
526 : shared_ptr<invocation_state> local_state =
527 : get_readable_state();
528 : typename connection_list_type::iterator it;
529 : for(it = local_state->connection_bodies().begin();
530 : it != local_state->connection_bodies().end(); ++it)
531 : {
532 : garbage_collecting_lock<connection_body_base> lock(**it);
533 : if((*it)->nolock_nograb_connected() == false) continue;
534 : if((*it)->slot().slot_function().contains(slot))
535 : {
536 : (*it)->nolock_disconnect(lock);
537 : }else
538 : { // check for wrapped extended slot
539 : bound_extended_slot_function_type *fp;
540 : fp = (*it)->slot().slot_function().template target<bound_extended_slot_function_type>();
541 : if(fp && fp->contains(slot))
542 : {
543 : (*it)->nolock_disconnect(lock);
544 : }else
545 : { // check for wrapped signal
546 : weak_signal_type *fp;
547 : fp = (*it)->slot().slot_function().template target<weak_signal_type>();
548 : if(fp && fp->contains(slot))
549 : {
550 : (*it)->nolock_disconnect(lock);
551 : }
552 : }
553 : }
554 : }
555 : }
556 : // connect slot
557 29777 : connection nolock_connect(garbage_collecting_lock<mutex_type> &lock,
558 : const slot_type &slot, connect_position position)
559 : {
560 : connection_body_type newConnectionBody =
561 29777 : create_new_connection(lock, slot);
562 29777 : group_key_type group_key;
563 29777 : if(position == at_back)
564 : {
565 29777 : group_key.first = back_ungrouped_slots;
566 29777 : _shared_state->connection_bodies().push_back(group_key, newConnectionBody);
567 29777 : }else
568 : {
569 0 : group_key.first = front_ungrouped_slots;
570 0 : _shared_state->connection_bodies().push_front(group_key, newConnectionBody);
571 : }
572 29777 : newConnectionBody->set_group_key(group_key);
573 29777 : return connection(newConnectionBody);
574 29777 : }
575 : connection nolock_connect(garbage_collecting_lock<mutex_type> &lock,
576 : const group_type &group,
577 : const slot_type &slot, connect_position position)
578 : {
579 : connection_body_type newConnectionBody =
580 : create_new_connection(lock, slot);
581 : // update map to first connection body in group if needed
582 : group_key_type group_key(grouped_slots, group);
583 : newConnectionBody->set_group_key(group_key);
584 : if(position == at_back)
585 : {
586 : _shared_state->connection_bodies().push_back(group_key, newConnectionBody);
587 : }else // at_front
588 : {
589 : _shared_state->connection_bodies().push_front(group_key, newConnectionBody);
590 : }
591 : return connection(newConnectionBody);
592 : }
593 :
594 : // _shared_state is mutable so we can do force_cleanup_connections during a const invocation
595 : mutable shared_ptr<invocation_state> _shared_state;
596 : mutable typename connection_list_type::iterator _garbage_collector_it;
597 : // connection list mutex must never be locked when attempting a blocking lock on a slot,
598 : // or you could deadlock.
599 : const boost::shared_ptr<mutex_type> _mutex;
600 : };
601 :
602 : }
603 :
604 : template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DEFAULTED_DECL(BOOST_SIGNALS2_NUM_ARGS)>
605 : class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
606 :
607 : template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
608 : class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
609 : BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION: public signal_base,
610 : public detail::BOOST_SIGNALS2_STD_FUNCTIONAL_BASE
611 : {
612 : typedef detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
613 : <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> impl_class;
614 : public:
615 : typedef typename impl_class::weak_signal_type weak_signal_type;
616 : friend class detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
617 : <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>;
618 :
619 : typedef SlotFunction slot_function_type;
620 : // typedef slotN<Signature, SlotFunction> slot_type;
621 : typedef typename impl_class::slot_type slot_type;
622 : typedef typename impl_class::extended_slot_function_type extended_slot_function_type;
623 : typedef typename impl_class::extended_slot_type extended_slot_type;
624 : typedef typename slot_function_type::result_type slot_result_type;
625 : typedef Combiner combiner_type;
626 : typedef typename impl_class::result_type result_type;
627 : typedef Group group_type;
628 : typedef GroupCompare group_compare_type;
629 : typedef typename impl_class::slot_call_iterator
630 : slot_call_iterator;
631 : typedef typename mpl::identity<BOOST_SIGNALS2_SIGNATURE_FUNCTION_TYPE(BOOST_SIGNALS2_NUM_ARGS)>::type signature_type;
632 :
633 : #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
634 :
635 : // typedef Tn argn_type;
636 : #define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \
637 : typedef BOOST_PP_CAT(T, BOOST_PP_INC(n)) BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(n)), _type);
638 : BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~)
639 : #undef BOOST_SIGNALS2_MISC_STATEMENT
640 : #if BOOST_SIGNALS2_NUM_ARGS == 1
641 : typedef arg1_type argument_type;
642 : #elif BOOST_SIGNALS2_NUM_ARGS == 2
643 : typedef arg1_type first_argument_type;
644 : typedef arg2_type second_argument_type;
645 : #endif
646 :
647 : template<unsigned n> class arg : public
648 : detail::BOOST_SIGNALS2_PREPROCESSED_ARG_N_TYPE_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
649 : <n BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
650 : BOOST_SIGNALS2_ARGS_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS)>
651 : {};
652 :
653 : BOOST_STATIC_CONSTANT(int, arity = BOOST_SIGNALS2_NUM_ARGS);
654 :
655 : #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
656 :
657 : template<unsigned n> class arg
658 : {
659 : public:
660 : typedef typename detail::variadic_arg_type<n, Args...>::type type;
661 : };
662 : BOOST_STATIC_CONSTANT(int, arity = sizeof...(Args));
663 :
664 : #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
665 :
666 179534 : BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg = combiner_type(),
667 : const group_compare_type &group_compare = group_compare_type()):
668 89767 : _pimpl(new impl_class(combiner_arg, group_compare))
669 269301 : {}
670 60446 : virtual ~BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)()
671 60446 : {
672 60446 : }
673 :
674 : //move support
675 : #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
676 : BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(
677 : BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) && other) BOOST_NOEXCEPT
678 : {
679 : using std::swap;
680 : swap(_pimpl, other._pimpl);
681 : }
682 :
683 : BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) &
684 : operator=(BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) && rhs) BOOST_NOEXCEPT
685 : {
686 : if(this == &rhs)
687 : {
688 : return *this;
689 : }
690 : _pimpl.reset();
691 : using std::swap;
692 : swap(_pimpl, rhs._pimpl);
693 : return *this;
694 : }
695 : #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
696 :
697 29777 : connection connect(const slot_type &slot, connect_position position = at_back)
698 : {
699 29777 : return (*_pimpl).connect(slot, position);
700 : }
701 : connection connect(const group_type &group,
702 : const slot_type &slot, connect_position position = at_back)
703 : {
704 : return (*_pimpl).connect(group, slot, position);
705 : }
706 : connection connect_extended(const extended_slot_type &slot, connect_position position = at_back)
707 : {
708 : return (*_pimpl).connect_extended(slot, position);
709 : }
710 : connection connect_extended(const group_type &group,
711 : const extended_slot_type &slot, connect_position position = at_back)
712 : {
713 : return (*_pimpl).connect_extended(group, slot, position);
714 : }
715 : void disconnect_all_slots()
716 : {
717 : if (_pimpl.get() == 0) return;
718 : (*_pimpl).disconnect_all_slots();
719 : }
720 : void disconnect(const group_type &group)
721 : {
722 : if (_pimpl.get() == 0) return;
723 : (*_pimpl).disconnect(group);
724 : }
725 : template <typename T>
726 : void disconnect(const T &slot)
727 : {
728 : if (_pimpl.get() == 0) return;
729 : (*_pimpl).disconnect(slot);
730 : }
731 940378 : result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
732 : {
733 940378 : return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
734 : }
735 : result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
736 : {
737 : return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
738 : }
739 : std::size_t num_slots() const
740 : {
741 : if (_pimpl.get() == 0) return 0;
742 : return (*_pimpl).num_slots();
743 : }
744 2371 : bool empty() const
745 : {
746 2371 : if (_pimpl.get() == 0) return true;
747 2371 : return (*_pimpl).empty();
748 2371 : }
749 : combiner_type combiner() const
750 : {
751 : return (*_pimpl).combiner();
752 : }
753 : void set_combiner(const combiner_type &combiner_arg)
754 : {
755 : return (*_pimpl).set_combiner(combiner_arg);
756 : }
757 : void swap(BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other) BOOST_NOEXCEPT
758 : {
759 : using std::swap;
760 : swap(_pimpl, other._pimpl);
761 : }
762 : bool operator==(const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other) const
763 : {
764 : return _pimpl.get() == other._pimpl.get();
765 : }
766 : bool null() const
767 : {
768 : return _pimpl.get() == 0;
769 : }
770 : protected:
771 6628 : virtual shared_ptr<void> lock_pimpl() const
772 : {
773 6628 : return _pimpl;
774 : }
775 : private:
776 : // explicit private copy constructor to avoid compiler trying to do implicit conversions to signal
777 : explicit BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(
778 : const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) &) BOOST_NOEXCEPT
779 : {
780 : // noncopyable
781 : BOOST_ASSERT(false);
782 : }
783 :
784 : shared_ptr<impl_class>
785 : _pimpl;
786 : };
787 :
788 : #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
789 : // free swap function for signalN classes, findable by ADL
790 : template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
791 : void swap(
792 : BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig1,
793 : BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig2 ) BOOST_NOEXCEPT
794 : {
795 : sig1.swap(sig2);
796 : }
797 : #endif
798 :
799 : namespace detail
800 : {
801 : // wrapper class for storing other signals as slots with automatic lifetime tracking
802 : template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
803 : class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
804 :
805 : template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
806 : class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
807 : BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION
808 : {
809 : public:
810 : typedef typename BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
811 : <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>::result_type
812 : result_type;
813 :
814 13256 : BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
815 : (const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
816 : <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>
817 : &signal):
818 6628 : _weak_pimpl(signal._pimpl)
819 13256 : {}
820 104603 : result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
821 : {
822 : shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
823 : <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> >
824 104603 : shared_pimpl(_weak_pimpl.lock());
825 104603 : return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
826 104603 : }
827 : result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
828 : {
829 : shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
830 : <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> >
831 : shared_pimpl(_weak_pimpl.lock());
832 : return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
833 : }
834 : bool contains(const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
835 : <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &signal) const
836 : {
837 : return _weak_pimpl.lock().get() == signal._pimpl.get();
838 : }
839 : template <typename T>
840 : bool contains(const T&) const
841 : {
842 : return false;
843 : }
844 : private:
845 : boost::weak_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
846 : <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > _weak_pimpl;
847 : };
848 :
849 : #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
850 : template<int arity, typename Signature>
851 : class extended_signature: public variadic_extended_signature<Signature>
852 : {};
853 : #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
854 : template<int arity, typename Signature>
855 : class extended_signature;
856 : // partial template specialization
857 : template<typename Signature>
858 : class extended_signature<BOOST_SIGNALS2_NUM_ARGS, Signature>
859 : {
860 : public:
861 : // typename function_traits<Signature>::result_type (
862 : // const boost::signals2::connection &,
863 : // typename function_traits<Signature>::arg1_type,
864 : // typename function_traits<Signature>::arg2_type,
865 : // ...,
866 : // typename function_traits<Signature>::argn_type)
867 : #define BOOST_SIGNALS2_EXT_SIGNATURE(arity, Signature) \
868 : typename function_traits<Signature>::result_type ( \
869 : const boost::signals2::connection & BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) \
870 : BOOST_PP_ENUM(arity, BOOST_SIGNALS2_SIGNATURE_TO_ARGN_TYPE, Signature) )
871 : typedef function<BOOST_SIGNALS2_EXT_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature)> function_type;
872 : #undef BOOST_SIGNALS2_EXT_SIGNATURE
873 : };
874 :
875 : template<unsigned arity, typename Signature, typename Combiner,
876 : typename Group, typename GroupCompare, typename SlotFunction,
877 : typename ExtendedSlotFunction, typename Mutex>
878 : class signalN;
879 : // partial template specialization
880 : template<typename Signature, typename Combiner, typename Group,
881 : typename GroupCompare, typename SlotFunction,
882 : typename ExtendedSlotFunction, typename Mutex>
883 : class signalN<BOOST_SIGNALS2_NUM_ARGS, Signature, Combiner, Group,
884 : GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex>
885 : {
886 : public:
887 : typedef BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)<
888 : BOOST_SIGNALS2_PORTABLE_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature),
889 : Combiner, Group,
890 : GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex> type;
891 : };
892 :
893 : #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
894 :
895 : } // namespace detail
896 : } // namespace signals2
897 : } // namespace boost
898 :
899 : #undef BOOST_SIGNALS2_NUM_ARGS
900 : #undef BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION
|