WPILibC++  2020.3.2-60-g3011ebe
Signal.h
1 /*----------------------------------------------------------------------------*/
2 /* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
3 /* Open Source Software - may be modified and shared by FRC teams. The code */
4 /* must be accompanied by the FIRST BSD license file in the root directory of */
5 /* the project. */
6 /*----------------------------------------------------------------------------*/
7 
8 /*
9 
10 Sigslot, a signal-slot library
11 
12 https://github.com/palacaze/sigslot
13 
14 MIT License
15 
16 Copyright (c) 2017 Pierre-Antoine Lacaze
17 
18 Permission is hereby granted, free of charge, to any person obtaining a copy
19 of this software and associated documentation files (the "Software"), to deal
20 in the Software without restriction, including without limitation the rights
21 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22 copies of the Software, and to permit persons to whom the Software is
23 furnished to do so, subject to the following conditions:
24 
25 The above copyright notice and this permission notice shall be included in all
26 copies or substantial portions of the Software.
27 
28 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34 SOFTWARE.
35  */
36 #pragma once
37 #include <atomic>
38 #include <functional>
39 #include <memory>
40 #include <type_traits>
41 #include <utility>
42 
43 #include "wpi/mutex.h"
44 
45 namespace wpi {
46 
47 namespace sig {
48 
49 namespace trait {
50 
52 template <typename...> struct typelist {};
53 
60 template<typename T>
61 std::weak_ptr<T> to_weak(std::weak_ptr<T> w) {
62  return w;
63 }
64 
65 template<typename T>
66 std::weak_ptr<T> to_weak(std::shared_ptr<T> s) {
67  return s;
68 }
69 
70 // tools
71 namespace detail {
72 
73 template <class...>
74 struct voider { using type = void; };
75 
76 // void_t from c++17
77 template <class...T>
78 using void_t = typename detail::voider<T...>::type;
79 
80 
81 template <typename, typename, typename = void, typename = void>
82 struct is_callable : std::false_type {};
83 
84 template <typename F, typename P, typename... T>
85 struct is_callable<F, P, typelist<T...>,
86  void_t<decltype(((*std::declval<P>()).*std::declval<F>())(std::declval<T>()...))>>
87  : std::true_type {};
88 
89 template <typename F, typename... T>
90 struct is_callable<F, typelist<T...>,
91  void_t<decltype(std::declval<F>()(std::declval<T>()...))>>
92  : std::true_type {};
93 
94 
95 template <typename T, typename = void>
96 struct is_weak_ptr : std::false_type {};
97 
98 template <typename T>
99 struct is_weak_ptr<T, void_t<decltype(std::declval<T>().expired()),
100  decltype(std::declval<T>().lock()),
101  decltype(std::declval<T>().reset())>>
102  : std::true_type {};
103 
104 template <typename T, typename = void>
105 struct is_weak_ptr_compatible : std::false_type {};
106 
107 template <typename T>
108 struct is_weak_ptr_compatible<T, void_t<decltype(to_weak(std::declval<T>()))>>
109  : is_weak_ptr<decltype(to_weak(std::declval<T>()))> {};
110 
111 } // namespace detail
112 
114 template <typename P>
115 constexpr bool is_weak_ptr_compatible_v = detail::is_weak_ptr_compatible<std::decay_t<P>>::value;
116 
118 template <typename L, typename... T>
119 constexpr bool is_callable_v = detail::is_callable<T..., L>::value;
120 
121 } // namespace trait
122 
123 
124 namespace detail {
125 
126 /* SlotState holds slot type independent state, to be used to interact with
127  * slots indirectly through connection and ScopedConnection objects.
128  */
129 class SlotState {
130 public:
131  constexpr SlotState() noexcept
132  : m_connected(true),
133  m_blocked(false) {}
134 
135  virtual ~SlotState() = default;
136 
137  bool connected() const noexcept { return m_connected; }
138  bool disconnect() noexcept { return m_connected.exchange(false); }
139 
140  bool blocked() const noexcept { return m_blocked.load(); }
141  void block() noexcept { m_blocked.store(true); }
142  void unblock() noexcept { m_blocked.store(false); }
143 
144 private:
145  std::atomic<bool> m_connected;
146  std::atomic<bool> m_blocked;
147 };
148 
149 } // namespace detail
150 
155 public:
156  ConnectionBlocker() = default;
157  ~ConnectionBlocker() noexcept { release(); }
158 
159  ConnectionBlocker(const ConnectionBlocker &) = delete;
160  ConnectionBlocker & operator=(const ConnectionBlocker &) = delete;
161 
162  ConnectionBlocker(ConnectionBlocker && o) noexcept
163  : m_state{std::move(o.m_state)}
164  {}
165 
166  ConnectionBlocker & operator=(ConnectionBlocker && o) noexcept {
167  release();
168  m_state.swap(o.m_state);
169  return *this;
170  }
171 
172 private:
173  friend class Connection;
174  ConnectionBlocker(std::weak_ptr<detail::SlotState> s) noexcept
175  : m_state{std::move(s)}
176  {
177  auto d = m_state.lock();
178  if (d) d->block();
179  }
180 
181  void release() noexcept {
182  auto d = m_state.lock();
183  if (d) d->unblock();
184  }
185 
186 private:
187  std::weak_ptr<detail::SlotState> m_state;
188 };
189 
190 
198 class Connection {
199 public:
200  Connection() = default;
201  virtual ~Connection() = default;
202 
203  Connection(const Connection &) noexcept = default;
204  Connection & operator=(const Connection &) noexcept = default;
205  Connection(Connection &&) noexcept = default;
206  Connection & operator=(Connection &&) noexcept = default;
207 
208  bool valid() const noexcept {
209  return !m_state.expired();
210  }
211 
212  bool connected() const noexcept {
213  const auto d = m_state.lock();
214  return d && d->connected();
215  }
216 
217  bool disconnect() noexcept {
218  auto d = m_state.lock();
219  return d && d->disconnect();
220  }
221 
222  bool blocked() const noexcept {
223  const auto d = m_state.lock();
224  return d && d->blocked();
225  }
226 
227  void block() noexcept {
228  auto d = m_state.lock();
229  if(d)
230  d->block();
231  }
232 
233  void unblock() noexcept {
234  auto d = m_state.lock();
235  if(d)
236  d->unblock();
237  }
238 
239  ConnectionBlocker blocker() const noexcept {
240  return ConnectionBlocker{m_state};
241  }
242 
243 protected:
244  template <typename, typename...> friend class SignalBase;
245  Connection(std::weak_ptr<detail::SlotState> s) noexcept
246  : m_state{std::move(s)}
247  {}
248 
249 protected:
250  std::weak_ptr<detail::SlotState> m_state;
251 };
252 
257 class ScopedConnection : public Connection {
258 public:
259  ScopedConnection() = default;
260  ~ScopedConnection() {
261  disconnect();
262  }
263 
264  ScopedConnection(const Connection &c) noexcept : Connection(c) {}
265  ScopedConnection(Connection &&c) noexcept : Connection(std::move(c)) {}
266 
267  ScopedConnection(const ScopedConnection &) noexcept = delete;
268  ScopedConnection & operator=(const ScopedConnection &) noexcept = delete;
269 
270  ScopedConnection(ScopedConnection && o) noexcept
271  : Connection{std::move(o.m_state)}
272  {}
273 
274  ScopedConnection & operator=(ScopedConnection && o) noexcept {
275  disconnect();
276  m_state.swap(o.m_state);
277  return *this;
278  }
279 
280 private:
281  template <typename, typename...> friend class SignalBase;
282  ScopedConnection(std::weak_ptr<detail::SlotState> s) noexcept
283  : Connection{std::move(s)}
284  {}
285 };
286 
287 namespace detail {
288 
289 template <typename...>
290 class SlotBase;
291 
292 template <typename... T>
293 using SlotPtr = std::shared_ptr<SlotBase<T...>>;
294 
295 /* A base class for slot objects. This base type only depends on slot argument
296  * types, it will be used as an element in an intrusive singly-linked list of
297  * slots, hence the public next member.
298  */
299 template <typename... Args>
300 class SlotBase : public SlotState {
301 public:
302  using base_types = trait::typelist<Args...>;
303 
304  virtual ~SlotBase() noexcept = default;
305 
306  // method effectively responsible for calling the "slot" function with
307  // supplied arguments whenever emission happens.
308  virtual void call_slot(Args...) = 0;
309 
310  template <typename... U>
311  void operator()(U && ...u) {
312  if (SlotState::connected() && !SlotState::blocked())
313  call_slot(std::forward<U>(u)...);
314  }
315 
316  SlotPtr<Args...> next;
317 };
318 
319 template <typename, typename...> class Slot {};
320 
321 /*
322  * A slot object holds state information, and a callable to to be called
323  * whenever the function call operator of its SlotBase base class is called.
324  */
325 template <typename Func, typename... Args>
326 class Slot<Func, trait::typelist<Args...>> : public SlotBase<Args...> {
327 public:
328  template <typename F>
329  constexpr Slot(F && f) : func{std::forward<F>(f)} {}
330 
331  virtual void call_slot(Args ...args) override {
332  func(args...);
333  }
334 
335 private:
336  std::decay_t<Func> func;
337 };
338 
339 /*
340  * Variation of slot that prepends a Connection object to the callable
341  */
342 template <typename Func, typename... Args>
343 class Slot<Func, trait::typelist<Connection&, Args...>> : public SlotBase<Args...> {
344 public:
345  template <typename F>
346  constexpr Slot(F && f) : func{std::forward<F>(f)} {}
347 
348  virtual void call_slot(Args ...args) override {
349  func(conn, args...);
350  }
351 
352  Connection conn;
353 
354 private:
355  std::decay_t<Func> func;
356 };
357 
358 /*
359  * A slot object holds state information, an object and a pointer over member
360  * function to be called whenever the function call operator of its SlotBase
361  * base class is called.
362  */
363 template <typename Pmf, typename Ptr, typename... Args>
364 class Slot<Pmf, Ptr, trait::typelist<Args...>> : public SlotBase<Args...> {
365 public:
366  template <typename F, typename P>
367  constexpr Slot(F && f, P && p)
368  : pmf{std::forward<F>(f)},
369  ptr{std::forward<P>(p)} {}
370 
371  virtual void call_slot(Args ...args) override {
372  ((*ptr).*pmf)(args...);
373  }
374 
375 private:
376  std::decay_t<Pmf> pmf;
377  std::decay_t<Ptr> ptr;
378 };
379 
380 /*
381  * Variation of slot that prepends a Connection object to the callable
382  */
383 template <typename Pmf, typename Ptr, typename... Args>
384 class Slot<Pmf, Ptr, trait::typelist<Connection&, Args...>> : public SlotBase<Args...> {
385 public:
386  template <typename F, typename P>
387  constexpr Slot(F && f, P && p)
388  : pmf{std::forward<F>(f)},
389  ptr{std::forward<P>(p)} {}
390 
391  virtual void call_slot(Args ...args) override {
392  ((*ptr).*pmf)(conn, args...);
393  }
394 
395  Connection conn;
396 
397 private:
398  std::decay_t<Pmf> pmf;
399  std::decay_t<Ptr> ptr;
400 };
401 
402 template <typename, typename, typename...> class SlotTracked {};
403 
404 /*
405  * An implementation of a slot that tracks the life of a supplied object
406  * through a weak pointer in order to automatically disconnect the slot
407  * on said object destruction.
408  */
409 template <typename Func, typename WeakPtr, typename... Args>
410 class SlotTracked<Func, WeakPtr, trait::typelist<Args...>> : public SlotBase<Args...> {
411 public:
412  template <typename F, typename P>
413  constexpr SlotTracked(F && f, P && p)
414  : func{std::forward<F>(f)},
415  ptr{std::forward<P>(p)}
416  {}
417 
418  virtual void call_slot(Args ...args) override {
419  if (! SlotState::connected())
420  return;
421  if (ptr.expired())
422  SlotState::disconnect();
423  else
424  func(args...);
425  }
426 
427 private:
428  std::decay_t<Func> func;
429  std::decay_t<WeakPtr> ptr;
430 };
431 
432 template <typename, typename, typename...> class SlotPmfTracked {};
433 
434 /*
435  * An implementation of a slot as a pointer over member function, that tracks
436  * the life of a supplied object through a weak pointer in order to automatically
437  * disconnect the slot on said object destruction.
438  */
439 template <typename Pmf, typename WeakPtr, typename... Args>
440 class SlotPmfTracked<Pmf, WeakPtr, trait::typelist<Args...>> : public SlotBase<Args...> {
441 public:
442  template <typename F, typename P>
443  constexpr SlotPmfTracked(F && f, P && p)
444  : pmf{std::forward<F>(f)},
445  ptr{std::forward<P>(p)}
446  {}
447 
448  virtual void call_slot(Args ...args) override {
449  if (! SlotState::connected())
450  return;
451  auto sp = ptr.lock();
452  if (!sp)
453  SlotState::disconnect();
454  else
455  ((*sp).*pmf)(args...);
456  }
457 
458 private:
459  std::decay_t<Pmf> pmf;
460  std::decay_t<WeakPtr> ptr;
461 };
462 
463 
464 // noop mutex for thread-unsafe use
465 struct NullMutex {
466  NullMutex() = default;
467  NullMutex(const NullMutex &) = delete;
468  NullMutex operator=(const NullMutex &) = delete;
469  NullMutex(NullMutex &&) = delete;
470  NullMutex operator=(NullMutex &&) = delete;
471 
472  bool try_lock() { return true; }
473  void lock() {}
474  void unlock() {}
475 };
476 
477 } // namespace detail
478 
479 
494 template <typename Lockable, typename... T>
495 class SignalBase {
496  using lock_type = std::unique_lock<Lockable>;
497  using SlotPtr = detail::SlotPtr<T...>;
498 
499  struct CallSlots {
500  SlotPtr m_slots;
501  SignalBase& m_base;
502 
503  CallSlots(SignalBase& base) : m_base(base) {}
504 
505  template <typename... A>
506  void operator()(A && ... a) {
507  SlotPtr *prev = nullptr;
508  SlotPtr *curr = m_slots ? &m_slots : nullptr;
509 
510  while (curr) {
511  // call non blocked, non connected slots
512  if ((*curr)->connected()) {
513  if (!m_base.m_block && !(*curr)->blocked())
514  (*curr)->operator()(a...);
515  prev = curr;
516  curr = (*curr)->next ? &((*curr)->next) : nullptr;
517  }
518  // remove slots marked as disconnected
519  else {
520  if (prev) {
521  (*prev)->next = (*curr)->next;
522  curr = (*prev)->next ? &((*prev)->next) : nullptr;
523  }
524  else
525  curr = (*curr)->next ? &((*curr)->next) : nullptr;
526  }
527  }
528  }
529  };
530 
531 public:
532  using arg_list = trait::typelist<T...>;
533  using ext_arg_list = trait::typelist<Connection&, T...>;
534 
535  SignalBase() noexcept : m_block(false) {}
536  ~SignalBase() {
537  disconnect_all();
538  }
539 
540  SignalBase(const SignalBase&) = delete;
541  SignalBase & operator=(const SignalBase&) = delete;
542 
543  SignalBase(SignalBase && o)
544  : m_block{o.m_block.load()}
545  {
546  lock_type lock(o.m_mutex);
547  std::swap(m_func, o.m_func);
548  }
549 
550  SignalBase & operator=(SignalBase && o) {
551  std::scoped_lock lock(m_mutex, o.m_mutex);
552 
553  std::swap(m_func, o.m_func);
554  m_block.store(o.m_block.exchange(m_block.load()));
555  return *this;
556  }
557 
570  template <typename... A>
571  void operator()(A && ... a) const {
572  lock_type lock(m_mutex);
573  if (!m_block && m_func) m_func(std::forward<A>(a)...);
574  }
575 
586  template <typename Callable>
587  void connect(Callable && c) {
588  if (!m_func) {
589  m_func = std::forward<Callable>(c);
590  } else {
591  using slot_t = detail::Slot<Callable, arg_list>;
592  auto s = std::make_shared<slot_t>(std::forward<Callable>(c));
593  add_slot(s);
594  }
595  }
596 
607  template <typename Callable>
608  std::enable_if_t<trait::is_callable_v<arg_list, Callable>, Connection>
609  connect_connection(Callable && c) {
610  using slot_t = detail::Slot<Callable, arg_list>;
611  auto s = std::make_shared<slot_t>(std::forward<Callable>(c));
612  add_slot(s);
613  return Connection(s);
614  }
615 
625  template <typename Callable>
626  std::enable_if_t<trait::is_callable_v<ext_arg_list, Callable>, Connection>
627  connect_extended(Callable && c) {
629  auto s = std::make_shared<slot_t>(std::forward<Callable>(c));
630  s->conn = Connection(s);
631  add_slot(s);
632  return Connection(s);
633  }
634 
642  template <typename Pmf, typename Ptr>
643  std::enable_if_t<trait::is_callable_v<arg_list, Pmf, Ptr> &&
644  !trait::is_weak_ptr_compatible_v<Ptr>, Connection>
645  connect(Pmf && pmf, Ptr && ptr) {
646  using slot_t = detail::Slot<Pmf, Ptr, arg_list>;
647  auto s = std::make_shared<slot_t>(std::forward<Pmf>(pmf), std::forward<Ptr>(ptr));
648  add_slot(s);
649  return Connection(s);
650  }
651 
659  template <typename Pmf, typename Ptr>
660  std::enable_if_t<trait::is_callable_v<ext_arg_list, Pmf, Ptr> &&
661  !trait::is_weak_ptr_compatible_v<Ptr>, Connection>
662  connect_extended(Pmf && pmf, Ptr && ptr) {
664  auto s = std::make_shared<slot_t>(std::forward<Pmf>(pmf), std::forward<Ptr>(ptr));
665  s->conn = Connection(s);
666  add_slot(s);
667  return Connection(s);
668  }
669 
686  template <typename Pmf, typename Ptr>
687  std::enable_if_t<!trait::is_callable_v<arg_list, Pmf> &&
688  trait::is_weak_ptr_compatible_v<Ptr>, Connection>
689  connect(Pmf && pmf, Ptr && ptr) {
690  using trait::to_weak;
691  auto w = to_weak(std::forward<Ptr>(ptr));
692  using slot_t = detail::SlotPmfTracked<Pmf, decltype(w), arg_list>;
693  auto s = std::make_shared<slot_t>(std::forward<Pmf>(pmf), w);
694  add_slot(s);
695  return Connection(s);
696  }
697 
714  template <typename Callable, typename Trackable>
715  std::enable_if_t<trait::is_callable_v<arg_list, Callable> &&
716  trait::is_weak_ptr_compatible_v<Trackable>, Connection>
717  connect(Callable && c, Trackable && ptr) {
718  using trait::to_weak;
719  auto w = to_weak(std::forward<Trackable>(ptr));
720  using slot_t = detail::SlotTracked<Callable, decltype(w), arg_list>;
721  auto s = std::make_shared<slot_t>(std::forward<Callable>(c), w);
722  add_slot(s);
723  return Connection(s);
724  }
725 
730  template <typename... CallArgs>
731  ScopedConnection connect_scoped(CallArgs && ...args) {
732  return connect_connection(std::forward<CallArgs>(args)...);
733  }
734 
739  void disconnect_all() {
740  lock_type lock(m_mutex);
741  clear();
742  }
743 
748  void block() noexcept {
749  m_block.store(true);
750  }
751 
756  void unblock() noexcept {
757  m_block.store(false);
758  }
759 
763  bool blocked() const noexcept {
764  return m_block.load();
765  }
766 
767 private:
768  template <typename S>
769  void add_slot(S &s) {
770  lock_type lock(m_mutex);
771  if (!m_func) {
772  // nothing stored
773  m_func = CallSlots(*this);
774  auto slots = m_func.template target<CallSlots>();
775  s->next = slots->m_slots;
776  slots->m_slots = s;
777  } else if (auto call_slots = m_func.template target<CallSlots>()) {
778  // already CallSlots
779  s->next = call_slots->m_slots;
780  call_slots->m_slots = s;
781  } else {
782  // was normal std::function, need to move it into a call slot
783  using slot_t = detail::Slot<std::function<void(T...)>, arg_list>;
784  auto s2 = std::make_shared<slot_t>(
785  std::forward<std::function<void(T...)>>(m_func));
786  m_func = CallSlots(*this);
787  auto slots = m_func.template target<CallSlots>();
788  s2->next = slots->m_slots;
789  s->next = s2;
790  slots->m_slots = s;
791  }
792  }
793 
794  void clear() {
795  m_func = nullptr;
796  }
797 
798 private:
799  std::function<void(T...)> m_func;
800  mutable Lockable m_mutex;
801  std::atomic<bool> m_block;
802 };
803 
809 template <typename... T>
810 using Signal = SignalBase<detail::NullMutex, T...>;
811 
821 template <typename... T>
822 using Signal_mt = SignalBase<mutex, T...>;
823 
829 template <typename... T>
830 using Signal_r = SignalBase<recursive_mutex, T...>;
831 
832 } // namespace sig
833 } // namespace wpi
wpi::sig::ConnectionBlocker
ConnectionBlocker is a RAII object that blocks a connection until destruction.
Definition: Signal.h:154
wpi::sig::SignalBase::connect_connection
std::enable_if_t< trait::is_callable_v< arg_list, Callable >, Connection > connect_connection(Callable &&c)
Connect a callable of compatible arguments, returning a Connection.
Definition: Signal.h:609
wpi::sig::SignalBase::connect_extended
std::enable_if_t< trait::is_callable_v< ext_arg_list, Callable >, Connection > connect_extended(Callable &&c)
Connect a callable with an additional Connection argument.
Definition: Signal.h:627
wpi::sig::SignalBase::block
void block() noexcept
Blocks signal emission Safety: thread safe.
Definition: Signal.h:748
wpi::sig::detail::Slot
Definition: Signal.h:319
wpi::sig::trait::typelist
represent a list of types
Definition: Signal.h:52
wpi::sig::SignalBase::connect
std::enable_if_t< trait::is_callable_v< arg_list, Callable > &&trait::is_weak_ptr_compatible_v< Trackable >, Connection > connect(Callable &&c, Trackable &&ptr)
Overload of connect for lifetime object tracking and automatic disconnection.
Definition: Signal.h:717
wpi::sig::SignalBase::connect_extended
std::enable_if_t< trait::is_callable_v< ext_arg_list, Pmf, Ptr > &&!trait::is_weak_ptr_compatible_v< Ptr >, Connection > connect_extended(Pmf &&pmf, Ptr &&ptr)
Overload of connect for pointer over member functions and.
Definition: Signal.h:662
wpi::sig::SignalBase::blocked
bool blocked() const noexcept
Tests blocking state of signal emission.
Definition: Signal.h:763
wpi::sig::detail::SlotPmfTracked
Definition: Signal.h:432
wpi::sig::trait::detail::is_weak_ptr_compatible
Definition: Signal.h:105
wpi::sig::detail::SlotBase
Definition: Signal.h:290
wpi::sig::trait::detail::voider
Definition: Signal.h:74
wpi::sig::SignalBase::unblock
void unblock() noexcept
Unblocks signal emission Safety: thread safe.
Definition: Signal.h:756
wpi::sig::detail::NullMutex
Definition: Signal.h:465
wpi
WPILib C++ utilities (wpiutil) namespace.
Definition: Endian.h:31
wpi::sig::detail::SlotTracked
Definition: Signal.h:402
wpi::sig::SignalBase::disconnect_all
void disconnect_all()
Disconnects all the slots Safety: Thread safety depends on locking policy.
Definition: Signal.h:739
wpi::sig::SignalBase::connect
std::enable_if_t< trait::is_callable_v< arg_list, Pmf, Ptr > &&!trait::is_weak_ptr_compatible_v< Ptr >, Connection > connect(Pmf &&pmf, Ptr &&ptr)
Overload of connect for pointers over member functions.
Definition: Signal.h:645
wpi::sig::SignalBase::connect
std::enable_if_t<!trait::is_callable_v< arg_list, Pmf > &&trait::is_weak_ptr_compatible_v< Ptr >, Connection > connect(Pmf &&pmf, Ptr &&ptr)
Overload of connect for lifetime object tracking and automatic disconnection.
Definition: Signal.h:689
wpi::sig::trait::detail::is_callable
Definition: Signal.h:82
wpi::sig::SignalBase::connect_scoped
ScopedConnection connect_scoped(CallArgs &&...args)
Creates a connection whose duration is tied to the return object Use the same semantics as connect.
Definition: Signal.h:731
wpi::sig::SignalBase::operator()
void operator()(A &&... a) const
Emit a signal.
Definition: Signal.h:571
wpi::sig::ScopedConnection
ScopedConnection is a RAII version of Connection It disconnects the slot from the signal upon destruc...
Definition: Signal.h:257
wpi::sig::Connection
A Connection object allows interaction with an ongoing slot connection.
Definition: Signal.h:198
wpi::sig::detail::SlotState
Definition: Signal.h:129
wpi::sig::SignalBase::connect
void connect(Callable &&c)
Connect a callable of compatible arguments.
Definition: Signal.h:587
wpi::sig::trait::detail::is_weak_ptr
Definition: Signal.h:96
wpi::sig::SignalBase
SignalBase is an implementation of the observer pattern, through the use of an emitting object and sl...
Definition: Signal.h:495