c++-gtk-utils
Classes | Namespaces | Typedefs | Functions
callback.h File Reference

This file provides classes for type erasure. More...

#include <functional>
#include <utility>
#include <cstddef>
#include <type_traits>
#include <glib.h>
#include <c++-gtk-utils/shared_ptr.h>
#include <c++-gtk-utils/param.h>
#include <c++-gtk-utils/cgu_config.h>

Go to the source code of this file.

Classes

class  Cgu::Callback::CallbackArg< FreeArgs >
 The callback interface class. More...
 
class  Cgu::Callback::CallbackArg< FreeArgs >
 The callback interface class. More...
 
class  Cgu::Callback::FunctorArg< FreeArgs >
 Functor class holding a Callback::CallbackArg object. More...
 
class  Cgu::Callback::SafeFunctorArg< FreeArgs >
 Functor class holding a Callback::CallbackArg object, with thread-safe reference count. More...
 
class  Cgu::Callback::FunctorArg< FreeArgs >
 Functor class holding a Callback::CallbackArg object. More...
 
class  Cgu::Callback::SafeFunctorArg< FreeArgs >
 Functor class holding a Callback::CallbackArg object, with thread-safe reference count. More...
 
class  Cgu::Callback::Callback0< T, FreeArgs >
 
class  Cgu::Callback::Callback1< unref, T, BoundArg, FreeArgs >
 
class  Cgu::Callback::Callback2< unref, T, BoundArg1, BoundArg2, FreeArgs >
 
class  Cgu::Callback::Callback3< unref, T, BoundArg1, BoundArg2, BoundArg3, FreeArgs >
 
class  Cgu::Callback::Callback4< unref, T, BoundArg1, BoundArg2, BoundArg3, BoundArg4, FreeArgs >
 
class  Cgu::Callback::Callback5< unref, T, BoundArg1, BoundArg2, BoundArg3, BoundArg4, BoundArg5, FreeArgs >
 
class  Cgu::Callback::Callback0_const< T, FreeArgs >
 
class  Cgu::Callback::Callback1_const< unref, T, BoundArg, FreeArgs >
 
class  Cgu::Callback::Callback2_const< unref, T, BoundArg1, BoundArg2, FreeArgs >
 
class  Cgu::Callback::Callback3_const< unref, T, BoundArg1, BoundArg2, BoundArg3, FreeArgs >
 
class  Cgu::Callback::Callback4_const< unref, T, BoundArg1, BoundArg2, BoundArg3, BoundArg4, FreeArgs >
 
class  Cgu::Callback::Callback5_const< unref, T, BoundArg1, BoundArg2, BoundArg3, BoundArg4, BoundArg5, FreeArgs >
 
class  Cgu::Callback::Callback0_static< FreeArgs >
 
class  Cgu::Callback::Callback1_static< unref, BoundArg, FreeArgs >
 
class  Cgu::Callback::Callback2_static< unref, BoundArg1, BoundArg2, FreeArgs >
 
class  Cgu::Callback::Callback3_static< unref, BoundArg1, BoundArg2, BoundArg3, FreeArgs >
 
class  Cgu::Callback::Callback4_static< unref, BoundArg1, BoundArg2, BoundArg3, BoundArg4, FreeArgs >
 
class  Cgu::Callback::Callback5_static< unref, BoundArg1, BoundArg2, BoundArg3, BoundArg4, BoundArg5, FreeArgs >
 
class  Cgu::Callback::Callback_lambda< Lambda, FreeArgs >
 

Namespaces

namespace  Cgu::Callback
 This namespace provides classes for type erasure.
 
namespace  Cgu
 

Typedefs

typedef CallbackArg Cgu::Callback::Callback
 
typedef FunctorArg Cgu::Callback::Functor
 
typedef SafeFunctorArg Cgu::Callback::SafeFunctor
 

Functions

template<class... T>
bool Cgu::Callback::operator== (const FunctorArg< T...> &f1, const FunctorArg< T...> &f2)
 
template<class... T>
bool Cgu::Callback::operator!= (const FunctorArg< T...> &f1, const FunctorArg< T...> &f2)
 
template<class... T>
bool Cgu::Callback::operator< (const FunctorArg< T...> &f1, const FunctorArg< T...> &f2)
 
template<class... T>
bool Cgu::Callback::operator== (const SafeFunctorArg< T...> &f1, const SafeFunctorArg< T...> &f2)
 
template<class... T>
bool Cgu::Callback::operator!= (const SafeFunctorArg< T...> &f1, const SafeFunctorArg< T...> &f2)
 
template<class... T>
bool Cgu::Callback::operator< (const SafeFunctorArg< T...> &f1, const SafeFunctorArg< T...> &f2)
 
template<class T , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (T &t, void(T::*func)(FreeArgs...))
 
template<class T , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (T &t, void(T::*func)(FreeArgs...))
 
template<class T , class BoundArg , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (T &t, void(T::*func)(BoundArg, FreeArgs...), BoundArg arg)
 
template<class T , class BoundArg , class Arg , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (T &t, void(T::*func)(BoundArg, FreeArgs...), Arg &&arg)
 
template<class T , class BoundArg1 , class BoundArg2 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (T &t, void(T::*func)(BoundArg1, BoundArg2, FreeArgs...), BoundArg1 arg1, BoundArg2 arg2)
 
template<class T , class BoundArg1 , class BoundArg2 , class Arg1 , class Arg2 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (T &t, void(T::*func)(BoundArg1, BoundArg2, FreeArgs...), Arg1 &&arg1, Arg2 &&arg2)
 
template<class T , class BoundArg1 , class BoundArg2 , class BoundArg3 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (T &t, void(T::*func)(BoundArg1, BoundArg2, BoundArg3, FreeArgs...), BoundArg1 arg1, BoundArg2 arg2, BoundArg3 arg3)
 
template<class T , class BoundArg1 , class BoundArg2 , class BoundArg3 , class Arg1 , class Arg2 , class Arg3 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (T &t, void(T::*func)(BoundArg1, BoundArg2, BoundArg3, FreeArgs...), Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3)
 
template<class T , class BoundArg1 , class BoundArg2 , class BoundArg3 , class BoundArg4 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (T &t, void(T::*func)(BoundArg1, BoundArg2, BoundArg3, BoundArg4, FreeArgs...), BoundArg1 arg1, BoundArg2 arg2, BoundArg3 arg3, BoundArg4 arg4)
 
template<class T , class BoundArg1 , class BoundArg2 , class BoundArg3 , class BoundArg4 , class Arg1 , class Arg2 , class Arg3 , class Arg4 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (T &t, void(T::*func)(BoundArg1, BoundArg2, BoundArg3, BoundArg4, FreeArgs...), Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4)
 
template<class T , class BoundArg1 , class BoundArg2 , class BoundArg3 , class BoundArg4 , class BoundArg5 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (T &t, void(T::*func)(BoundArg1, BoundArg2, BoundArg3, BoundArg4, BoundArg5, FreeArgs...), BoundArg1 arg1, BoundArg2 arg2, BoundArg3 arg3, BoundArg4 arg4, BoundArg5 arg5)
 
template<class T , class BoundArg1 , class BoundArg2 , class BoundArg3 , class BoundArg4 , class BoundArg5 , class Arg1 , class Arg2 , class Arg3 , class Arg4 , class Arg5 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (T &t, void(T::*func)(BoundArg1, BoundArg2, BoundArg3, BoundArg4, BoundArg5, FreeArgs...), Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5)
 
template<class T , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (const T &t, void(T::*func)(FreeArgs...) const)
 
template<class T , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (const T &t, void(T::*func)(FreeArgs...) const)
 
template<class T , class BoundArg , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (const T &t, void(T::*func)(BoundArg, FreeArgs...) const, BoundArg arg)
 
template<class T , class BoundArg , class Arg , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (const T &t, void(T::*func)(BoundArg, FreeArgs...) const, Arg &&arg)
 
template<class T , class BoundArg1 , class BoundArg2 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (const T &t, void(T::*func)(BoundArg1, BoundArg2, FreeArgs...) const, BoundArg1 arg1, BoundArg2 arg2)
 
template<class T , class BoundArg1 , class BoundArg2 , class Arg1 , class Arg2 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (const T &t, void(T::*func)(BoundArg1, BoundArg2, FreeArgs...) const, Arg1 &&arg1, Arg2 &&arg2)
 
template<class T , class BoundArg1 , class BoundArg2 , class BoundArg3 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (const T &t, void(T::*func)(BoundArg1, BoundArg2, BoundArg3, FreeArgs...) const, BoundArg1 arg1, BoundArg2 arg2, BoundArg3 arg3)
 
template<class T , class BoundArg1 , class BoundArg2 , class BoundArg3 , class Arg1 , class Arg2 , class Arg3 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (const T &t, void(T::*func)(BoundArg1, BoundArg2, BoundArg3, FreeArgs...) const, Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3)
 
template<class T , class BoundArg1 , class BoundArg2 , class BoundArg3 , class BoundArg4 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (const T &t, void(T::*func)(BoundArg1, BoundArg2, BoundArg3, BoundArg4, FreeArgs...) const, BoundArg1 arg1, BoundArg2 arg2, BoundArg3 arg3, BoundArg4 arg4)
 
template<class T , class BoundArg1 , class BoundArg2 , class BoundArg3 , class BoundArg4 , class Arg1 , class Arg2 , class Arg3 , class Arg4 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (const T &t, void(T::*func)(BoundArg1, BoundArg2, BoundArg3, BoundArg4, FreeArgs...) const, Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4)
 
template<class T , class BoundArg1 , class BoundArg2 , class BoundArg3 , class BoundArg4 , class BoundArg5 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (const T &t, void(T::*func)(BoundArg1, BoundArg2, BoundArg3, BoundArg4, BoundArg5, FreeArgs...) const, BoundArg1 arg1, BoundArg2 arg2, BoundArg3 arg3, BoundArg4 arg4, BoundArg5 arg5)
 
template<class T , class BoundArg1 , class BoundArg2 , class BoundArg3 , class BoundArg4 , class BoundArg5 , class Arg1 , class Arg2 , class Arg3 , class Arg4 , class Arg5 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (const T &t, void(T::*func)(BoundArg1, BoundArg2, BoundArg3, BoundArg4, BoundArg5, FreeArgs...) const, Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5)
 
template<class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (void(*func)(FreeArgs...))
 
template<class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (void(*func)(FreeArgs...))
 
template<class BoundArg , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (void(*func)(BoundArg, FreeArgs...), BoundArg arg)
 
template<class BoundArg , class Arg , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (void(*func)(BoundArg, FreeArgs...), Arg &&arg)
 
template<class BoundArg1 , class BoundArg2 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (void(*func)(BoundArg1, BoundArg2, FreeArgs...), BoundArg1 arg1, BoundArg2 arg2)
 
template<class BoundArg1 , class BoundArg2 , class Arg1 , class Arg2 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (void(*func)(BoundArg1, BoundArg2, FreeArgs...), Arg1 &&arg1, Arg2 &&arg2)
 
template<class BoundArg1 , class BoundArg2 , class BoundArg3 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (void(*func)(BoundArg1, BoundArg2, BoundArg3, FreeArgs...), BoundArg1 arg1, BoundArg2 arg2, BoundArg3 arg3)
 
template<class BoundArg1 , class BoundArg2 , class BoundArg3 , class Arg1 , class Arg2 , class Arg3 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (void(*func)(BoundArg1, BoundArg2, BoundArg3, FreeArgs...), Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3)
 
template<class BoundArg1 , class BoundArg2 , class BoundArg3 , class BoundArg4 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (void(*func)(BoundArg1, BoundArg2, BoundArg3, BoundArg4, FreeArgs...), BoundArg1 arg1, BoundArg2 arg2, BoundArg3 arg3, BoundArg4 arg4)
 
template<class BoundArg1 , class BoundArg2 , class BoundArg3 , class BoundArg4 , class Arg1 , class Arg2 , class Arg3 , class Arg4 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (void(*func)(BoundArg1, BoundArg2, BoundArg3, BoundArg4, FreeArgs...), Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4)
 
template<class BoundArg1 , class BoundArg2 , class BoundArg3 , class BoundArg4 , class BoundArg5 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (void(*func)(BoundArg1, BoundArg2, BoundArg3, BoundArg4, BoundArg5, FreeArgs...), BoundArg1 arg1, BoundArg2 arg2, BoundArg3 arg3, BoundArg4 arg4, BoundArg5 arg5)
 
template<class BoundArg1 , class BoundArg2 , class BoundArg3 , class BoundArg4 , class BoundArg5 , class Arg1 , class Arg2 , class Arg3 , class Arg4 , class Arg5 , class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (void(*func)(BoundArg1, BoundArg2, BoundArg3, BoundArg4, BoundArg5, FreeArgs...), Arg1 &&arg1, Arg2 &&arg2, Arg3 &&arg3, Arg4 &&arg4, Arg5 &&arg5)
 
template<class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (const std::function< void(FreeArgs...)> &f)
 
template<class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (const std::function< void(FreeArgs...)> &f)
 
template<class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make (std::function< void(FreeArgs...)> &&f)
 
template<class... FreeArgs>
CallbackArg< FreeArgs...> * Cgu::Callback::make_ref (std::function< void(FreeArgs...)> &&f)
 
template<class... FreeArgs, class Lambda >
CallbackArg< FreeArgs...> * Cgu::Callback::lambda (Lambda &&l)
 
void Cgu::Callback::post (const Callback *cb, gint priority=G_PRIORITY_DEFAULT_IDLE, GMainContext *context=0)
 
void Cgu::Callback::post (const Callback *cb, Releaser &r, gint priority=G_PRIORITY_DEFAULT_IDLE, GMainContext *context=0)
 
template<class F , class = typename std::enable_if<!std::is_convertible<typename std::remove_reference<F>::type, const Callback*>::value>::type>
void Cgu::Callback::post (F &&func, gint priority=G_PRIORITY_DEFAULT_IDLE, GMainContext *context=0)
 
template<class F , class = typename std::enable_if<!std::is_convertible<typename std::remove_reference<F>::type, const Callback*>::value>::type>
void Cgu::Callback::post (F &&func, Releaser &r, gint priority=G_PRIORITY_DEFAULT_IDLE, GMainContext *context=0)
 

Detailed Description

This file provides classes for type erasure.

#include <c++-gtk-utils/callback.h>

These classes provide type erasure on callable objects. They comprise a generic callback creation and execution interface for closures. There is a basic Callback::Callback type, which is an entire closure or 'thunk', where all values are bound into the object, and is completely opaque. Callback::CallbackArg<T...> is a class which takes unbound arguments of the template types when the object is dispatched. (The opaque Callback::Callback type is a typedef for Callback::CallbackArg<>: the two types are interchangeable.)

The classes are normally constructed using the Callback::lambda() factory function, which takes any callable object such as a lambda expression or the return value of std::bind and returns a pointer to a Callback or CallbackArg object. When using Callback::lambda(), the unbound arguments (if any) must be passed as explicit template parameters.

Callback/CallbackArg objects can also be constructed using the Callback::make() and Callback::make_ref() factory functions, which can be useful where invoking standalone functions or object methods.

The Callback::make() and Callback::make_ref() functions

The Callback::make() and Callback::make_ref() functions construct a Callback/CallbackArg object from a function pointer (or an object reference and member function pointer) together with bound arguments. They provide for a maximum of five bound arguments, and the unbound arguments (if any) must be the last (trailing) arguments of the relevant function or method to be called.

Callback::make() does a direct type mapping from the bound arguments of the function or method represented by the callback object to the arguments stored by it and is for use when all bound arguments are simple fundamental types such as pointers (including C strings), integers or floating points.

Callback::make_ref() is for use where bound arguments include class types or one or more of the types of the bound arguments include a const reference. It will accomplish perfect forwarding (by lvalue reference or rvalue reference) when constructing the callback and will also ensure that a copy of any object to be passed by const reference (as well as any taken by value) is kept in order to avoid dangling references. Note however that where a member function is called, the object of which the target function is a member must still be in existence when the Callback/CallbackArg object is dispatched and, unlike Callback::make(), Callback::make_ref() cannot be used with overloaded functions except with explicit disambiguation.

Callback::make() can also construct a Callback/CallbackArg object from a std::function object.

Callback::FunctorArg and Callback::SafeFunctorArg classes

Functor/FunctorArg objects hold a Callback/CallbackArg object by SharedPtr to enable them to be shared by reference counting, and SafeFunctor/SafeFunctorArg objects hold them by SharedLockPtr, which have a thread safe reference count so that they may be shared between different threads. These classes also have an operator()() method so as to be callable with function syntax.

Memory allocation

If the library is installed using the --with-glib-memory-slices-no-compat configuration option, any Callback/CallbackArg object will be constructed in glib memory slices rather than in the generic C++ free store.

Usage

Using Callback::lambda():

using namespace Cgu;
// here cb1 is of type Callback::Callback*
auto cb1 = Callback::lambda<>([] () {std::cout << "Hello world\n";});
cb1->dispatch();
delete cb1;
// the same using Callback::Functor
Callback::Functor f1{Callback::lambda<>([] () {std::cout << "Hello world\n";})};
f1();
// here cb2 is of type Callback::CallbackArg<int, int&>*
auto cb2 = Callback::lambda<int, int&>([] (int i, int& j) {j = 10 * i;});
int res;
cb2->dispatch(2, res);
std::cout << "10 times 2 is " << res << '\n';
delete cb2;
// the same using Callback::FunctorArg
Callback::FunctorArg<int, int&> f2{Callback::lambda<int, int&>([] (int i, int& j) {j = 10 * i;})};
f2(2, res);
std::cout << "10 times 2 is " << res << '\n';

Using Callback::make(), with a class object my_obj of type MyClass, with a method void MyClass::my_method(int, int, const char*):

using namespace Cgu;
int arg1 = 1, arg2 = 5;
// here cb1 is of type Callback::Callback*
auto cb1 = Callback::make(my_obj, &MyClass::my_method, arg1, arg2, "Hello\n");
cb1->dispatch();
delete cb1;
// the same using Callback::Functor
Callback::Functor f{Callback::make(my_obj, &MyClass::my_method, arg1, arg2, "Hello\n")};
f();
int arg1 = 1, arg2 = 5;
// cb2 is of type Callback::CallbackArg<int, const char*>*
auto cb = Callback::make(my_obj, &MyClass::my_method, arg1);
cb->dispatch(arg2, "Hello\n");
delete cb;
// the same using Callback::FunctorArg
Callback::FunctorArg<int, const char*> f{Callback::make(my_obj, &MyClass::my_method, arg1)};
f(arg2, "Hello\n");

Using Callback::make_ref(), with a class object my_obj of type MyClass, with a method void MyClass::my_method(int, const Something&):

int arg1 = 1;
Something arg2;
// here cb is of type Callback::Callback*
auto cb = Callback::make_ref(my_obj, &MyClass::my_method, arg1, arg2);

Posting of callbacks

This file also provides Callback::post() functions which will execute a callback in a glib main loop and can be used (amongst other things) to pass an event from a worker thread to the main program thread. In that respect, it provides an alternative to the Notifier class. It is passed either a pointer to a Callback::Callback object created with a call to Callback::lambda() (or Callback::make(), Callback::make_ref()), or it can be passed a callable object and the implementation will call Callback::lambda() for you.

To provide for thread-safe automatic disconnection of the callback if the object whose method it represents or calls into is destroyed before the callback executes in the main loop, include a Releaser as a public member of that object and pass the Releaser object as the second argument of Callback::post(). Note that for this to be race free, the lifetime of the remote object whose method is to be invoked must be determined by the thread to whose main loop the callback has been attached. When the main loop begins invoking the execution of the callback, the remote object must either wholly exist (in which case the callback will be invoked) or have been destroyed (in which case the callback will be ignored), and not be in some transient half-state governed by another thread.

Advantages as against Notifier:

  1. If there are a lot of different events requiring callbacks to be dispatched in the program from worker threads to the main thread, this avoids having separate Notifier objects for each event.
  2. It is easier to pass arguments with varying values - they can be passed as arguments to the Callback::make functions and no special synchronisation is normally required (the call to g_source_attach() invokes locking of the main loop which will have the effect of ensuring memory visibility). With a Notifier object it may be necessary to use an asynchronous queue to pass variable values (or to bind a reference to the data, thus normally requiring separate synchronisation).
  3. Although the callback would normally be sent for execution by the main program loop, and that is the default, it can be sent for execution by any thread which has its own GMainContext/GMainLoop objects. Thus callbacks can be passed for execution between worker threads, or from the main program thread to worker threads, as well as from worker threads to the main program thread.

Disadvantages as against Notifier:

  1. Less efficient, as a new callback object has to be created on freestore every time the callback is invoked, together with a new Emitter object if a Releaser is used to track the callback.
  2. Multiple callbacks relevant to a single event cannot be invoked from a single call for the event - each callback has to be separately dispatched.