Lely core libraries  1.9.2
doc/util/callback.md
1 Callback interface
2 ==================
3 
4 Many [objects](@ref md_doc_util_object) in the Lely libraries allow the user to
5 register callback functions. The function signature and registration method all
6 follow the pattern shown here.
7 
8 Example of a public C header (lely/lib/obj.h):
9 ~~~{.c}
10 #ifdef __cplusplus
11 // Ensure that callback functions also use the C calling convention.
12 extern "C" {
13 #endif
14 
15 // The last argument of a callback function is always a pointer to
16 // user-specified data.
17 typedef void callback_func_t(Args... args, void *data);
18 
19 // Retrieves a pointer to the callback function and the user-specified data.
20 void obj_get_func(const obj_t *obj, callback_func_t **pfunc, void **pdata);
21 
22 // Sets a callback function. The data pointer is passed as the last argument in
23 // each invocation of func.
24 void obj_set_func(obj_t *obj, callback_func_t *func, void *data);
25 
26 #ifdef __cplusplus
27 }
28 #endif
29 ~~~
30 
31 Example of the C implementation (obj.c):
32 ~~~{.c}
33 struct obj {
34  ...
35  callback_func_t *callback_func;
36  void *callback_data;
37  ...
38 };
39 
40 // An internal helper function that invokes the callback if it is set.
41 static void obj_callback(obj_t *obj, Args... args);
42 
43 struct __obj *
44 __obj_init(struct __obj *obj, Args... args)
45 {
46  ...
47 
48  obj->callback_func = NULL;
49  obj->callback_data = NULL;
50 
51  ...
52 }
53 
54 void
55 obj_get_func(const obj_t *obj, callback_func_t **pfunc, void **pdata)
56 {
57  assert(obj);
58 
59  if (pfunc)
60  *pfunc = obj->callback_func;
61  if (pdata)
62  *pdata = obj->callback_data;
63 }
64 
65 void
66 obj_set_func(obj_t *obj, callback_func_t *func, void *data)
67 {
68  assert(obj);
69 
70  obj->callback_func = func;
71  obj->callback_data = data;
72 }
73 
74 static void
75 obj_callback(obj_t *obj, Args... args)
76 {
77  assert(obj);
78 
79  if (obj->callback_func)
80  obj->callback_func(args..., obj->callback_data);
81 }
82 ~~~
83 
84 The user-specified data pointer can be used to allow the registration of C++
85 function objects or member functions. lely/util/c_call.hpp provides several
86 templates to automatically generate the required wrapper functions.
87 
88 Example of a public C++ header (lely/lib/obj.hpp):
89 ~~~{.cpp}
90 // Include the c_obj_call<>, c_mem_call<> and c_mem_fn<> templates.
91 #include <lely/util/c_call.hpp>
92 
93 namespace lely {
94 
95 class Obj {
96 public:
97  ...
98 
99  void
100  getFunc(callback_func_t** pfunc, void** pdata) const noexcept
101  {
102  obj_get_func(this, pfunc, pdata);
103  }
104 
105  // Registers a C-style callback function. The user specifies the data
106  // pointer.
107  void
108  setFunc(callback_func_t* func, void* data) noexcept
109  {
110  obj_set_func(this, func, data);
111  }
112 
113  // Registers a function object as the callback. The data pointer is used
114  // to store the address of the function object and is therefore not
115  // available to the user.
116  template <class F>
117  void
118  setFunc(F* f) noexcept
119  {
120  setFunc(&c_obj_call<callback_func_t*, F>::function,
121  static_cast<void*>(f));
122  }
123 
124  // Registers a member function as the callback. The first template
125  // parameter is the class containing the member function, the second is
126  // the address of the member function. The data pointer is used to store
127  // the address of the class instance and is therefore not available to
128  // the user.
129  template <class C, typename c_mem_fn<callback_func_t*, C>::type M>
130  void
131  setFunc(C* obj) noexcept
132  {
133  setFunc(&c_mem_call<callback_func_t*, C, M>::function,
134  static_cast<void*>(obj));
135  }
136 
137  ...
138 };
139 
140 } // lely
141 ~~~
142 
143 Registering a C-style global (or static) function in C++ is similar to C:
144 ~~~{.cpp}
145 void myFunc(Args... args, void* data) noexcept;
146 
147 void
148 setFunc(Obj* obj, void* data)
149 {
150  obj->setFunc(&myFunc, data);
151 }
152 ~~~
153 
154 The second form of `setFunc()` allows registering a function object. The user is
155 responsible for lifetime of the object.
156 ~~~{.cpp}
157 struct MyFuncObj {
158  void operator()(Args... args) noexcept;
159 };
160 
161 void
162 setFunc(Obj* obj, MyFuncObj* f)
163 {
164  obj->setFunc(f);
165 }
166 ~~~
167 
168 The third form of `setFunc()` allows member functions to be registered as
169 callbacks. Again, the user is responsible for the lifetime of the instance of
170 the class containing the member function.
171 ~~~{.cpp}
172 class MyClass {
173 public:
174  void myFunc(Args... args) noexcept;
175 };
176 
177 void
178 setFunc(Obj* obj, MyClass* cls)
179 {
180  obj->setFunc<MyClass, &MyClass::myFunc>(cls);
181 }
182 ~~~
183 It is also possible to register private methods as callbacks, but only from a
184 function which has private access (i.e., a friend or another method).
185