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