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 | BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg, |
159 | const group_compare_type &group_compare): |
160 | _shared_state(boost::make_shared<invocation_state>(connection_list_type(group_compare), combiner_arg)), |
161 | _garbage_collector_it(_shared_state->connection_bodies().end()), |
162 | _mutex(new mutex_type()) |
163 | {} |
164 | // connect slot |
165 | connection connect(const slot_type &slot, connect_position position = at_back) |
166 | { |
167 | garbage_collecting_lock<mutex_type> lock(*_mutex); |
168 | return nolock_connect(lock, slot, position); |
169 | } |
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 | result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) |
230 | { |
231 | shared_ptr<invocation_state> local_state; |
232 | typename connection_list_type::iterator it; |
233 | { |
234 | garbage_collecting_lock<mutex_type> list_lock(*_mutex); |
235 | // only clean up if it is safe to do so |
236 | if(_shared_state.unique()) |
237 | nolock_cleanup_connections(lock&: list_lock, grab_tracked: false, count: 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 | local_state = _shared_state; |
242 | } |
243 | slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); |
244 | slot_call_iterator_cache_type cache(invoker); |
245 | invocation_janitor janitor(cache, *this, &local_state->connection_bodies()); |
246 | return detail::combiner_invoker<typename combiner_type::result_type>() |
247 | ( |
248 | local_state->combiner(), |
249 | slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache), |
250 | slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache) |
251 | ); |
252 | } |
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(lock&: list_lock, grab_tracked: false, count: 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 | bool empty() const |
291 | { |
292 | shared_ptr<invocation_state> local_state = |
293 | get_readable_state(); |
294 | typename connection_list_type::iterator it; |
295 | for(it = local_state->connection_bodies().begin(); |
296 | it != local_state->connection_bodies().end(); ++it) |
297 | { |
298 | if((*it)->connected()) return false; |
299 | } |
300 | return true; |
301 | } |
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 | invocation_state(const connection_list_type &connections_in, |
387 | const combiner_type &combiner_in): _connection_bodies(new connection_list_type(connections_in)), |
388 | _combiner(new combiner_type(combiner_in)) |
389 | {} |
390 | invocation_state(const invocation_state &other, const connection_list_type &connections_in): |
391 | _connection_bodies(new connection_list_type(connections_in)), |
392 | _combiner(other._combiner) |
393 | {} |
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 | connection_list_type & connection_bodies() { return *_connection_bodies; } |
399 | const connection_list_type & connection_bodies() const { return *_connection_bodies; } |
400 | 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 | invocation_janitor |
415 | ( |
416 | const slot_call_iterator_cache_type &cache, |
417 | const signal_type &sig, |
418 | const connection_list_type *connection_bodies |
419 | ):_cache(cache), _sig(sig), _connection_bodies(connection_bodies) |
420 | {} |
421 | ~invocation_janitor() |
422 | { |
423 | // force a full cleanup of disconnected slots if there are too many |
424 | if(_cache.disconnected_slot_count > _cache.connected_slot_count) |
425 | { |
426 | _sig.force_cleanup_connections(_connection_bodies); |
427 | } |
428 | } |
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 | 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 | BOOST_ASSERT(_shared_state.unique()); |
441 | typename connection_list_type::iterator it; |
442 | unsigned i; |
443 | for(it = begin, i = 0; |
444 | it != _shared_state->connection_bodies().end() && (count == 0 || i < count); |
445 | ++i) |
446 | { |
447 | bool connected; |
448 | if(grab_tracked) |
449 | (*it)->disconnect_expired_slot(lock); |
450 | connected = (*it)->nolock_nograb_connected(); |
451 | if(connected == false) |
452 | { |
453 | it = _shared_state->connection_bodies().erase((*it)->group_key(), it); |
454 | }else |
455 | { |
456 | ++it; |
457 | } |
458 | } |
459 | _garbage_collector_it = it; |
460 | } |
461 | // clean up a few connections in constant time |
462 | void nolock_cleanup_connections(garbage_collecting_lock<mutex_type> &lock, |
463 | bool grab_tracked, unsigned count) const |
464 | { |
465 | BOOST_ASSERT(_shared_state.unique()); |
466 | typename connection_list_type::iterator begin; |
467 | if(_garbage_collector_it == _shared_state->connection_bodies().end()) |
468 | { |
469 | begin = _shared_state->connection_bodies().begin(); |
470 | }else |
471 | { |
472 | begin = _garbage_collector_it; |
473 | } |
474 | nolock_cleanup_connections_from(lock, grab_tracked, begin, count); |
475 | } |
476 | /* Make a new copy of the slot list if it is currently being read somewhere else |
477 | */ |
478 | void nolock_force_unique_connection_list(garbage_collecting_lock<mutex_type> &lock) |
479 | { |
480 | if(_shared_state.unique() == false) |
481 | { |
482 | _shared_state = boost::make_shared<invocation_state>(*_shared_state, _shared_state->connection_bodies()); |
483 | nolock_cleanup_connections_from(lock, grab_tracked: true, begin: _shared_state->connection_bodies().begin()); |
484 | }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 | nolock_cleanup_connections(lock, grab_tracked: true, count: 2); |
490 | } |
491 | } |
492 | // force a full cleanup of the connection list |
493 | void force_cleanup_connections(const connection_list_type *connection_bodies) const |
494 | { |
495 | 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 | if(&_shared_state->connection_bodies() != connection_bodies) |
499 | { |
500 | return; |
501 | } |
502 | if(_shared_state.unique() == false) |
503 | { |
504 | _shared_state = boost::make_shared<invocation_state>(*_shared_state, _shared_state->connection_bodies()); |
505 | } |
506 | nolock_cleanup_connections_from(lock&: list_lock, grab_tracked: false, begin: _shared_state->connection_bodies().begin()); |
507 | } |
508 | shared_ptr<invocation_state> get_readable_state() const |
509 | { |
510 | unique_lock<mutex_type> list_lock(*_mutex); |
511 | return _shared_state; |
512 | } |
513 | connection_body_type create_new_connection(garbage_collecting_lock<mutex_type> &lock, |
514 | const slot_type &slot) |
515 | { |
516 | nolock_force_unique_connection_list(lock); |
517 | 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 | connection nolock_connect(garbage_collecting_lock<mutex_type> &lock, |
558 | const slot_type &slot, connect_position position) |
559 | { |
560 | connection_body_type newConnectionBody = |
561 | create_new_connection(lock, slot); |
562 | group_key_type group_key; |
563 | if(position == at_back) |
564 | { |
565 | group_key.first = back_ungrouped_slots; |
566 | _shared_state->connection_bodies().push_back(group_key, newConnectionBody); |
567 | }else |
568 | { |
569 | group_key.first = front_ungrouped_slots; |
570 | _shared_state->connection_bodies().push_front(group_key, newConnectionBody); |
571 | } |
572 | newConnectionBody->set_group_key(group_key); |
573 | return connection(newConnectionBody); |
574 | } |
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 | 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 | _pimpl(new impl_class(combiner_arg, group_compare)) |
669 | {} |
670 | virtual ~BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)() |
671 | { |
672 | } |
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 | connection connect(const slot_type &slot, connect_position position = at_back) |
698 | { |
699 | 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 | (*_pimpl).disconnect_all_slots(); |
718 | } |
719 | void disconnect(const group_type &group) |
720 | { |
721 | (*_pimpl).disconnect(group); |
722 | } |
723 | template <typename T> |
724 | void disconnect(const T &slot) |
725 | { |
726 | (*_pimpl).disconnect(slot); |
727 | } |
728 | result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) |
729 | { |
730 | return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); |
731 | } |
732 | result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const |
733 | { |
734 | return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); |
735 | } |
736 | std::size_t num_slots() const |
737 | { |
738 | return (*_pimpl).num_slots(); |
739 | } |
740 | bool empty() const |
741 | { |
742 | return (*_pimpl).empty(); |
743 | } |
744 | combiner_type combiner() const |
745 | { |
746 | return (*_pimpl).combiner(); |
747 | } |
748 | void set_combiner(const combiner_type &combiner_arg) |
749 | { |
750 | return (*_pimpl).set_combiner(combiner_arg); |
751 | } |
752 | void swap(BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other) BOOST_NOEXCEPT |
753 | { |
754 | using std::swap; |
755 | swap(_pimpl, other._pimpl); |
756 | } |
757 | bool operator==(const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other) const |
758 | { |
759 | return _pimpl.get() == other._pimpl.get(); |
760 | } |
761 | protected: |
762 | virtual shared_ptr<void> lock_pimpl() const |
763 | { |
764 | return _pimpl; |
765 | } |
766 | private: |
767 | // explicit private copy constructor to avoid compiler trying to do implicit conversions to signal |
768 | explicit BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)( |
769 | const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other) BOOST_NOEXCEPT |
770 | { |
771 | // noncopyable |
772 | BOOST_ASSERT(false); |
773 | } |
774 | |
775 | shared_ptr<impl_class> |
776 | _pimpl; |
777 | }; |
778 | |
779 | #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES |
780 | // free swap function for signalN classes, findable by ADL |
781 | template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> |
782 | void swap( |
783 | BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig1, |
784 | BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig2 ) BOOST_NOEXCEPT |
785 | { |
786 | sig1.swap(sig2); |
787 | } |
788 | #endif |
789 | |
790 | namespace detail |
791 | { |
792 | // wrapper class for storing other signals as slots with automatic lifetime tracking |
793 | template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> |
794 | class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS); |
795 | |
796 | template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)> |
797 | class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) |
798 | BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION |
799 | { |
800 | public: |
801 | typedef typename BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) |
802 | <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>::result_type |
803 | result_type; |
804 | |
805 | BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) |
806 | (const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) |
807 | <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> |
808 | &signal): |
809 | _weak_pimpl(signal._pimpl) |
810 | {} |
811 | result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) |
812 | { |
813 | shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) |
814 | <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > |
815 | shared_pimpl(_weak_pimpl.lock()); |
816 | return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); |
817 | } |
818 | result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const |
819 | { |
820 | shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) |
821 | <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > |
822 | shared_pimpl(_weak_pimpl.lock()); |
823 | return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); |
824 | } |
825 | bool contains(const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) |
826 | <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &signal) const |
827 | { |
828 | return _weak_pimpl.lock().get() == signal._pimpl.get(); |
829 | } |
830 | template <typename T> |
831 | bool contains(const T&) const |
832 | { |
833 | return false; |
834 | } |
835 | private: |
836 | boost::weak_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) |
837 | <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > _weak_pimpl; |
838 | }; |
839 | |
840 | #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES |
841 | template<int arity, typename Signature> |
842 | class extended_signature: public variadic_extended_signature<Signature> |
843 | {}; |
844 | #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES |
845 | template<int arity, typename Signature> |
846 | class extended_signature; |
847 | // partial template specialization |
848 | template<typename Signature> |
849 | class extended_signature<BOOST_SIGNALS2_NUM_ARGS, Signature> |
850 | { |
851 | public: |
852 | // typename function_traits<Signature>::result_type ( |
853 | // const boost::signals2::connection &, |
854 | // typename function_traits<Signature>::arg1_type, |
855 | // typename function_traits<Signature>::arg2_type, |
856 | // ..., |
857 | // typename function_traits<Signature>::argn_type) |
858 | #define BOOST_SIGNALS2_EXT_SIGNATURE(arity, Signature) \ |
859 | typename function_traits<Signature>::result_type ( \ |
860 | const boost::signals2::connection & BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) \ |
861 | BOOST_PP_ENUM(arity, BOOST_SIGNALS2_SIGNATURE_TO_ARGN_TYPE, Signature) ) |
862 | typedef function<BOOST_SIGNALS2_EXT_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature)> function_type; |
863 | #undef BOOST_SIGNALS2_EXT_SIGNATURE |
864 | }; |
865 | |
866 | template<unsigned arity, typename Signature, typename Combiner, |
867 | typename Group, typename GroupCompare, typename SlotFunction, |
868 | typename ExtendedSlotFunction, typename Mutex> |
869 | class signalN; |
870 | // partial template specialization |
871 | template<typename Signature, typename Combiner, typename Group, |
872 | typename GroupCompare, typename SlotFunction, |
873 | typename ExtendedSlotFunction, typename Mutex> |
874 | class signalN<BOOST_SIGNALS2_NUM_ARGS, Signature, Combiner, Group, |
875 | GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex> |
876 | { |
877 | public: |
878 | typedef BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)< |
879 | BOOST_SIGNALS2_PORTABLE_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature), |
880 | Combiner, Group, |
881 | GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex> type; |
882 | }; |
883 | |
884 | #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES |
885 | |
886 | } // namespace detail |
887 | } // namespace signals2 |
888 | } // namespace boost |
889 | |
890 | #undef BOOST_SIGNALS2_NUM_ARGS |
891 | #undef BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION |
892 | |