1 // Boost.Signals library
3 // Copyright Douglas Gregor 2001-2004. Use, modification and
4 // distribution is subject to the Boost Software License, Version
5 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
8 // For more information, see http://www.boost.org
10 // This file intentionally does not have include guards, because it is meant
11 // to be included multiple times (one for each signalN class). The
12 // BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED macro merely serves to
13 // suppress reinclusion of the files that this header depends on.
15 #ifndef BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED
16 #define BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED
17 # include <boost/config.hpp>
18 # include <boost/signals/connection.hpp>
19 # include <boost/ref.hpp>
20 # include <boost/signals/slot.hpp>
21 # include <boost/last_value.hpp>
22 # include <boost/signals/detail/signal_base.hpp>
23 # include <boost/signals/detail/slot_call_iterator.hpp>
24 # include <boost/mpl/bool.hpp>
25 # include <boost/type_traits/is_convertible.hpp>
27 # include <functional>
29 #endif // !BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED
31 #ifdef BOOST_HAS_ABI_HEADERS
32 # include BOOST_ABI_PREFIX
35 // Include the appropriate functionN header
36 #define BOOST_SIGNAL_FUNCTION_N_HEADER BOOST_JOIN(<boost/function/function,BOOST_SIGNALS_NUM_ARGS.hpp>)
37 #include BOOST_SIGNAL_FUNCTION_N_HEADER
39 // Determine if a comma should follow a listing of the arguments/parameters
40 #if BOOST_SIGNALS_NUM_ARGS == 0
41 # define BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
43 # define BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS ,
44 #endif // BOOST_SIGNALS_NUM_ARGS > 0
46 // Define class names used
47 #define BOOST_SIGNALS_SIGNAL BOOST_JOIN(signal,BOOST_SIGNALS_NUM_ARGS)
48 #define BOOST_SIGNALS_FUNCTION BOOST_JOIN(function,BOOST_SIGNALS_NUM_ARGS)
49 #define BOOST_SIGNALS_ARGS_STRUCT BOOST_JOIN(args,BOOST_SIGNALS_NUM_ARGS)
50 #define BOOST_SIGNALS_CALL_BOUND BOOST_JOIN(call_bound,BOOST_SIGNALS_NUM_ARGS)
52 // Define commonly-used instantiations
53 #define BOOST_SIGNALS_ARGS_STRUCT_INST \
54 BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS>
57 namespace BOOST_SIGNALS_NAMESPACE {
59 // Holds the arguments for a bound slot call in a single place
60 template<BOOST_SIGNALS_TEMPLATE_PARMS
61 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
63 struct BOOST_SIGNALS_ARGS_STRUCT {
64 BOOST_SIGNALS_ARGS_STRUCT(BOOST_SIGNALS_COPY_PARMS)
65 BOOST_SIGNALS_INIT_ARGS
69 BOOST_SIGNALS_ARGS_AS_MEMBERS
72 // Function object that calls the function object given to it, passing
73 // the bound arguments along to that underlying function object
75 struct BOOST_SIGNALS_CALL_BOUND {
76 template<BOOST_SIGNALS_TEMPLATE_PARMS
77 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
80 typedef BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS>*
85 typedef R result_type;
88 caller(args_type a) : args(a) {}
90 template<typename Pair>
91 R operator()(const Pair& slot) const
93 F* target = const_cast<F*>(unsafe_any_cast<F>(&slot.second));
94 return (*target)(BOOST_SIGNALS_BOUND_ARGS);
100 struct BOOST_SIGNALS_CALL_BOUND<void> {
101 template<BOOST_SIGNALS_TEMPLATE_PARMS
102 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
105 typedef BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS>*
110 typedef unusable result_type;
112 caller(args_type a) : args(a) {}
114 template<typename Pair>
115 unusable operator()(const Pair& slot) const
117 F* target = const_cast<F*>(unsafe_any_cast<F>(&slot.second));
118 (*target)(BOOST_SIGNALS_BOUND_ARGS);
123 } // namespace detail
124 } // namespace BOOST_SIGNALS_NAMESPACE
126 // The actual signalN class
129 BOOST_SIGNALS_TEMPLATE_PARMS
130 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
131 typename Combiner = last_value<R>,
132 typename Group = int,
133 typename GroupCompare = std::less<Group>,
134 typename SlotFunction = BOOST_SIGNALS_FUNCTION<
135 R BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
136 BOOST_SIGNALS_TEMPLATE_ARGS>
138 class BOOST_SIGNALS_SIGNAL :
139 public BOOST_SIGNALS_NAMESPACE::detail::signal_base, // management of slot list
140 public BOOST_SIGNALS_NAMESPACE::trackable // signals are trackable
143 // The slot function type
144 typedef SlotFunction slot_function_type;
146 // Result type of a slot
147 typedef typename BOOST_SIGNALS_NAMESPACE::detail::slot_result_type<R>::type
151 BOOST_SIGNALS_ARG_TYPES
153 #if BOOST_SIGNALS_NUM_ARGS == 1
154 typedef T1 argument_type;
155 #elif BOOST_SIGNALS_NUM_ARGS == 2
156 typedef T1 first_argument_type;
157 typedef T2 second_argument_type;
161 // The real slot name comparison object type
162 typedef BOOST_SIGNALS_NAMESPACE::detail::group_bridge_compare<GroupCompare, Group>
163 real_group_compare_type;
165 // The function object passed to the slot call iterator that will call
166 // the underlying slot function with its arguments bound
167 typedef BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_CALL_BOUND<R>
168 outer_bound_slot_caller;
169 typedef typename outer_bound_slot_caller::template
170 caller<BOOST_SIGNALS_TEMPLATE_ARGS
171 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
176 // Combiner's result type
177 typedef typename Combiner::result_type result_type;
180 typedef Combiner combiner_type;
183 typedef slot<slot_function_type> slot_type;
185 // Slot name type and comparison
186 typedef Group group_type;
187 typedef GroupCompare group_compare_type;
189 typedef BOOST_SIGNALS_NAMESPACE::detail::slot_call_iterator<
190 call_bound_slot, iterator> slot_call_iterator;
193 BOOST_SIGNALS_SIGNAL(const Combiner& c = Combiner(),
194 const GroupCompare& comp = GroupCompare()) :
195 BOOST_SIGNALS_NAMESPACE::detail::signal_base(real_group_compare_type(comp),
200 // Connect a slot to this signal
201 BOOST_SIGNALS_NAMESPACE::connection
202 connect(const slot_type&,
203 BOOST_SIGNALS_NAMESPACE::connect_position at
204 = BOOST_SIGNALS_NAMESPACE::at_back);
207 BOOST_SIGNALS_NAMESPACE::connection
208 connect(const group_type&, const slot_type&,
209 BOOST_SIGNALS_NAMESPACE::connect_position at
210 = BOOST_SIGNALS_NAMESPACE::at_back);
213 void disconnect(const T& t)
215 typedef mpl::bool_<(is_convertible<T, group_type>::value)> is_group;
216 this->do_disconnect(t, is_group());
220 // Disconnect a named slot
221 void do_disconnect(const group_type& group, mpl::bool_<true>)
223 impl->disconnect(group);
226 template<typename Function>
227 void do_disconnect(const Function& f, mpl::bool_<false>)
229 // Notify the slot handling code that we are iterating through the slots
230 BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl);
232 for (iterator i = impl->slots_.begin(); i != impl->slots_.end(); ++i) {
233 slot_function_type& s = *unsafe_any_cast<slot_function_type>(&i->second);
234 if (s == f) i->first.disconnect();
241 result_type operator()(BOOST_SIGNALS_PARMS);
242 result_type operator()(BOOST_SIGNALS_PARMS) const;
245 { return *unsafe_any_cast<Combiner>(&impl->combiner_); }
247 const Combiner& combiner() const
248 { return *unsafe_any_cast<const Combiner>(&impl->combiner_); }
253 BOOST_SIGNALS_TEMPLATE_PARMS
254 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
257 typename GroupCompare,
258 typename SlotFunction
260 BOOST_SIGNALS_NAMESPACE::connection
261 BOOST_SIGNALS_SIGNAL<
262 R, BOOST_SIGNALS_TEMPLATE_ARGS
263 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
264 Combiner, Group, GroupCompare, SlotFunction
265 >::connect(const slot_type& in_slot,
266 BOOST_SIGNALS_NAMESPACE::connect_position at)
268 using boost::BOOST_SIGNALS_NAMESPACE::detail::stored_group;
270 // If the slot has been disconnected, just return a disconnected
272 if (!in_slot.is_active()) {
273 return BOOST_SIGNALS_NAMESPACE::connection();
276 return impl->connect_slot(in_slot.get_slot_function(), stored_group(),
277 in_slot.get_data(), at);
282 BOOST_SIGNALS_TEMPLATE_PARMS
283 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
286 typename GroupCompare,
287 typename SlotFunction
289 BOOST_SIGNALS_NAMESPACE::connection
290 BOOST_SIGNALS_SIGNAL<
291 R, BOOST_SIGNALS_TEMPLATE_ARGS
292 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
293 Combiner, Group, GroupCompare, SlotFunction
294 >::connect(const group_type& group,
295 const slot_type& in_slot,
296 BOOST_SIGNALS_NAMESPACE::connect_position at)
298 // If the slot has been disconnected, just return a disconnected
300 if (!in_slot.is_active()) {
301 return BOOST_SIGNALS_NAMESPACE::connection();
304 return impl->connect_slot(in_slot.get_slot_function(), group,
305 in_slot.get_data(), at);
310 BOOST_SIGNALS_TEMPLATE_PARMS
311 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
314 typename GroupCompare,
315 typename SlotFunction
317 typename BOOST_SIGNALS_SIGNAL<
318 R, BOOST_SIGNALS_TEMPLATE_ARGS
319 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
320 Combiner, Group, GroupCompare, SlotFunction>::result_type
321 BOOST_SIGNALS_SIGNAL<
322 R, BOOST_SIGNALS_TEMPLATE_ARGS
323 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
324 Combiner, Group, GroupCompare, SlotFunction
325 >::operator()(BOOST_SIGNALS_PARMS)
327 // Notify the slot handling code that we are making a call
328 BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl);
330 // Construct a function object that will call the underlying slots
331 // with the given arguments.
332 #if BOOST_SIGNALS_NUM_ARGS == 0
333 BOOST_SIGNALS_ARGS_STRUCT_INST args;
335 BOOST_SIGNALS_ARGS_STRUCT_INST args(BOOST_SIGNALS_ARGS);
336 #endif // BOOST_SIGNALS_NUM_ARGS > 0
337 call_bound_slot f(&args);
339 typedef typename call_bound_slot::result_type call_result_type;
340 optional<call_result_type> cache;
341 // Let the combiner call the slots via a pair of input iterators
342 return combiner()(slot_call_iterator(notification.impl->slots_.begin(),
343 impl->slots_.end(), f, cache),
344 slot_call_iterator(notification.impl->slots_.end(),
345 impl->slots_.end(), f, cache));
350 BOOST_SIGNALS_TEMPLATE_PARMS
351 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
354 typename GroupCompare,
355 typename SlotFunction
357 typename BOOST_SIGNALS_SIGNAL<
358 R, BOOST_SIGNALS_TEMPLATE_ARGS
359 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
360 Combiner, Group, GroupCompare, SlotFunction>::result_type
361 BOOST_SIGNALS_SIGNAL<
362 R, BOOST_SIGNALS_TEMPLATE_ARGS
363 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
364 Combiner, Group, GroupCompare, SlotFunction
365 >::operator()(BOOST_SIGNALS_PARMS) const
367 // Notify the slot handling code that we are making a call
368 BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl);
370 // Construct a function object that will call the underlying slots
371 // with the given arguments.
372 #if BOOST_SIGNALS_NUM_ARGS == 0
373 BOOST_SIGNALS_ARGS_STRUCT_INST args;
375 BOOST_SIGNALS_ARGS_STRUCT_INST args(BOOST_SIGNALS_ARGS);
376 #endif // BOOST_SIGNALS_NUM_ARGS > 0
378 call_bound_slot f(&args);
380 typedef typename call_bound_slot::result_type call_result_type;
381 optional<call_result_type> cache;
383 // Let the combiner call the slots via a pair of input iterators
384 return combiner()(slot_call_iterator(notification.impl->slots_.begin(),
385 impl->slots_.end(), f, cache),
386 slot_call_iterator(notification.impl->slots_.end(),
387 impl->slots_.end(), f, cache));
391 #undef BOOST_SIGNAL_FUNCTION_N_HEADER
392 #undef BOOST_SIGNALS_ARGS_STRUCT_INST
393 #undef BOOST_SIGNALS_CALL_BOUND
394 #undef BOOST_SIGNALS_ARGS_STRUCT
395 #undef BOOST_SIGNALS_FUNCTION
396 #undef BOOST_SIGNALS_SIGNAL
397 #undef BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
399 #ifdef BOOST_HAS_ABI_HEADERS
400 # include BOOST_ABI_SUFFIX