1 #ifndef _SIGC_FUNCTORS_SLOT_H_
2 #define _SIGC_FUNCTORS_SLOT_H_
4 #include <sigc++/trackable.h>
5 #include <sigc++/visit_each.h>
6 #include <sigc++/adaptors/adaptor_trait.h>
7 #include <sigc++/functors/slot_base.h>
14 * A typed slot_rep holds a functor that can be invoked from
15 * slot::operator()(). visit_each() is used to visit the functor's
16 * targets that inherit trackable recursively and register the
17 * notification callback. Consequently the slot_rep object will be
18 * notified when some referred object is destroyed or overwritten.
20 template <class T_functor>
21 struct typed_slot_rep : public slot_rep
24 using self = typed_slot_rep<T_functor>;
27 /* Use an adaptor type so that arguments can be passed as const references
28 * through explicit template instantiation from slot_call#::call_it() */
29 using adaptor_type = typename adaptor_trait<T_functor>::adaptor_type;
31 /** The functor contained by this slot_rep object. */
32 adaptor_type functor_;
34 /** Constructs an invalid typed slot_rep object.
35 * The notification callback is registered using visit_each().
36 * @param functor The functor contained by the new slot_rep object.
38 inline typed_slot_rep(const T_functor& functor)
39 : slot_rep(nullptr, &destroy, &dup), functor_(functor)
40 { sigc::visit_each_type<trackable*>(slot_do_bind(this), functor_); }
42 inline typed_slot_rep(const typed_slot_rep& cl)
43 : slot_rep(cl.call_, &destroy, &dup), functor_(cl.functor_)
44 { sigc::visit_each_type<trackable*>(slot_do_bind(this), functor_); }
46 typed_slot_rep& operator=(const typed_slot_rep& src) = delete;
48 typed_slot_rep(typed_slot_rep&& src) = delete;
49 typed_slot_rep& operator=(typed_slot_rep&& src) = delete;
51 inline ~typed_slot_rep()
55 sigc::visit_each_type<trackable*>(slot_do_unbind(this), functor_);
59 /** Detaches the stored functor from the other referred trackables and destroys it.
60 * This does not destroy the base slot_rep object.
62 static void destroy(notifiable* data)
64 self* self_ = static_cast<self*>(reinterpret_cast<slot_rep*>(data));
65 self_->call_ = nullptr;
66 self_->destroy_ = nullptr;
67 sigc::visit_each_type<trackable*>(slot_do_unbind(self_), self_->functor_);
68 self_->functor_.~adaptor_type();
69 /* don't call disconnect() here: destroy() is either called
70 * a) from the parent itself (in which case disconnect() leads to a segfault) or
71 * b) from a parentless slot (in which case disconnect() does nothing)
75 /** Makes a deep copy of the slot_rep object.
76 * Deep copy means that the notification callback of the new
77 * slot_rep object is registered in the referred trackables.
78 * @return A deep copy of the slot_rep object.
80 static slot_rep* dup(slot_rep* a_rep)
82 return new self(*static_cast<self*>(a_rep));
87 /** Abstracts functor execution.
88 * call_it() invokes a functor of type @e T_functor with a list of
89 * parameters whose types are given by the template arguments.
90 * address() forms a function pointer from call_it().
92 * The following template arguments are used:
93 * - @e T_functor The functor type.
94 * - @e T_return The return type of call_it().
95 * - @e T_arg Argument types used in the definition of call_it().
98 template<class T_functor, class T_return, class... T_arg>
101 /** Invokes a functor of type @p T_functor.
102 * @param rep slot_rep object that holds a functor of type @p T_functor.
103 * @param _A_a Arguments to be passed on to the functor.
104 * @return The return values of the functor invocation.
106 static T_return call_it(slot_rep* rep, type_trait_take_t<T_arg>... a_)
108 using typed_slot = typed_slot_rep<T_functor>;
109 typed_slot *typed_rep = static_cast<typed_slot*>(rep);
110 return (typed_rep->functor_).template operator()<type_trait_take_t<T_arg>...>
114 /** Forms a function pointer from call_it().
115 * @return A function pointer formed from call_it().
117 static hook address()
118 { return reinterpret_cast<hook>(&call_it); }
122 } /* namespace internal */
125 // Because slot is opaque, visit_each() will not visit its internal members.
126 // Those members are not reachable by visit_each() after the slot has been
127 // constructed. But when a slot contains another slot, the outer slot will become
128 // the parent of the inner slot, with similar results. See the description of
129 // slot's specialization of the visitor struct.
131 /** Converts an arbitrary functor to a unified type which is opaque.
132 * sigc::slot itself is a functor or, to be more precise, a closure. It contains
133 * a single, arbitrary functor (or closure) that is executed in operator()().
135 * The template arguments determine the function signature of operator()():
136 * - @e T_return The return type of operator()().
137 * - @e T_arg Argument types used in the definition of operator()().
139 * For instance, to declare a slot that returns void and takes two parameters
142 * sigc::slot<void(bool, int)> some_slot;
145 * To use, simply assign the desired functor to the slot. If the functor
146 * is not compatible with the parameter list defined with the template
147 * arguments then compiler errors are triggered. When called, the slot
148 * will invoke the functor with minimal copies.
149 * block() and unblock() can be used to block the functor's invocation
150 * from operator()() temporarily.
154 template <class T_return, class... T_arg>
157 template <class T_return, class... T_arg>
158 class slot<T_return(T_arg...)>
162 using result_type = T_return;
163 //TODO: using arg_type_ = type_trait_take_t<T_arg>;
165 #ifndef DOXYGEN_SHOULD_SKIP_THIS
167 using rep_type = internal::slot_rep;
169 using call_type = T_return (*)(rep_type*, type_trait_take_t<T_arg>...);
172 /** Invoke the contained functor unless slot is in blocking state.
173 * @param _A_a Arguments to be passed on to the functor.
174 * @return The return value of the functor invocation.
176 inline T_return operator()(type_trait_take_t<T_arg>... _A_a) const
178 if (!empty() && !blocked())
179 return (reinterpret_cast<call_type>(slot_base::rep_->call_))(slot_base::rep_, _A_a...);
185 /** Constructs a slot from an arbitrary functor.
186 * @param _A_func The desired functor the new slot should be assigned to.
188 template <class T_functor>
189 slot(const T_functor& _A_func)
190 : slot_base(new internal::typed_slot_rep<T_functor>(_A_func))
192 //The slot_base:: is necessary to stop the HP-UX aCC compiler from being confused. murrayc.
193 slot_base::rep_->call_ = internal::slot_call<T_functor, T_return, T_arg...>::address();
196 /** Constructs a slot, copying an existing one.
197 * @param src The existing slot to copy.
199 slot(const slot& src)
203 /** Constructs a slot, moving an existing one.
204 * If @p src is connected to a parent (e.g. a signal), it is copied, not moved.
205 * @param src The existing slot to move or copy.
208 : slot_base(std::move(src))
211 /** Overrides this slot, making a copy from another slot.
212 * @param src The slot from which to make a copy.
215 slot& operator=(const slot& src)
217 slot_base::operator=(src);
221 /** Overrides this slot, making a move from another slot.
222 * If @p src is connected to a parent (e.g. a signal), it is copied, not moved.
223 * @param src The slot from which to move or copy.
226 slot& operator=(slot&& src)
228 slot_base::operator=(std::move(src));
233 #ifndef DOXYGEN_SHOULD_SKIP_THIS
234 //template specialization of visitor<>::do_visit_each<>(action, functor):
235 /** Performs a functor on each of the targets of a functor.
237 * There are three function overloads for sigc::slot.
239 * The first two overloads are very specialized. They handle the (probably unusual)
240 * case when the functor, stored in a slot, contains a slot. They are invoked from
241 * the constructor, destructor or destroy() method of typed_slot_rep.
242 * The first overload, called from the constructor of the outer slot, sets
243 * the outer slot as the parent of the inner slot. The second overload, called from
244 * the destructor or destroy() of the outer slot, unsets the parent of the inner slot.
245 * When an object referenced from the inner slot is deleted, the inner slot calls
246 * its slot_rep::disconnect(), which calls the outer slot's slot_rep::notify().
247 * The outer slot is informed just as if one of its directly referenced objects
248 * had been deleted. Result: The outer slot is disconnected from its parent,
249 * if any (for instance a sigc::signal).
250 * See https://bugzilla.gnome.org/show_bug.cgi?id=755003
252 * The third overload is identical to do_visit_each() in visitor's primary template.
256 template <typename T_return, typename... T_arg>
257 struct visitor<slot<T_return, T_arg...>>
259 static void do_visit_each(const internal::limit_derived_target<trackable*, internal::slot_do_bind>& _A_action,
260 const slot<T_return, T_arg...>& _A_target)
262 if (_A_target.rep_ && _A_target.rep_->parent_ == nullptr)
263 _A_target.rep_->set_parent(_A_action.action_.rep_, &internal::slot_rep::notify);
266 static void do_visit_each(const internal::limit_derived_target<trackable*, internal::slot_do_unbind>& _A_action,
267 const slot<T_return, T_arg...>& _A_target)
269 if (_A_target.rep_ && _A_target.rep_->parent_ == _A_action.action_.rep_)
270 _A_target.rep_->set_parent(nullptr, nullptr);
273 template <typename T_action>
274 static void do_visit_each(const T_action& _A_action,
275 const slot<T_return, T_arg...>& _A_target)
277 _A_action(_A_target);
280 #endif // DOXYGEN_SHOULD_SKIP_THIS
282 } /* namespace sigc */
284 #endif /* _SIGC_FUNCTORS_SLOT_H_ */