Callback interface
Many objects in the Lely core libraries allow the user to register callback functions. The function signature and registration methods all follow the pattern shown here.
Example of a public C header (lely/lib/obj.h):
#ifndef LELY_LIB_OBJ_H_
#define LELY_LIB_OBJ_H_
typedef struct obj obj_t;
#ifdef __cplusplus
// Ensure that callback functions also use the C calling convention.
extern "C" {
#endif
// The last argument of a callback function is always a pointer to
// user-specified data.
typedef void callback_func_t(Args... args, void *data);
// Retrieves a pointer to the callback function and the user-specified data.
void obj_get_func(const obj_t *obj, callback_func_t **pfunc, void **pdata);
// Sets a callback function. The data pointer is passed as the last argument in
// each invocation of func.
void obj_set_func(obj_t *obj, callback_func_t *func, void *data);
#ifdef __cplusplus
}
#endif
#endif // !LELY_LIB_OBJ_H_
Example of the C implementation (obj.c):
#include <lely/lib/obj.h>
#include <assert.h>
struct obj {
	...
	callback_func_t *callback_func;
	void *callback_data;
	...
};
// An internal helper function that invokes the callback if it is set.
static void obj_callback(obj_t *obj, Args... args);
struct obj *
obj_init(struct obj *obj, Args... args)
{
	...
	obj->callback_func = NULL;
	obj->callback_data = NULL;
	...
}
void
obj_get_func(const obj_t *obj, callback_func_t **pfunc, void **pdata)
{
	assert(obj);
	if (pfunc)
		*pfunc = obj->callback_func;
	if (pdata)
		*pdata = obj->callback_data;
}
void
obj_set_func(obj_t *obj, callback_func_t *func, void *data)
{
	assert(obj);
	obj->callback_func = func;
	obj->callback_data = data;
}
static void
obj_callback(obj_t *obj, Args... args)
{
	assert(obj);
	if (obj->callback_func)
		obj->callback_func(args..., obj->callback_data);
}
The user-specified data pointer can be used to allow the registration of C++ function objects or member functions.
Example of a public C++ header (lely/lib/obj.hpp):
#ifndef LELY_LIB_OBJ_HPP_
#define LELY_LIB_OBJ_HPP_
#include <lely/lib/obj.h>
namespace lely {
namespace lib {
class Object {
 public:
  ...
  void
  get_func(callback_func_t** pfunc, void** pdata = nullptr) const noexcept {
    obj_get_func(*this, pfunc, pdata);
  }
  // Registers a C-style callback function. The user specifies the data pointer.
  void
  set_func(callback_func_t* func, void* data) noexcept {
    obj_set_func(*this, func, data);
  }
  // Registers a function object as the callback. The data pointer is used to
  // store the address of the function object and is therefore not available to
  // the user.
  template <class F>
  void
  set_func(F* f) noexcept {
    set_func(
        [](Args... args, void* data) noexcept {
          auto f = static_cast<F*>(data);
          (*f)(args...);
        },
        static_cast<void*>(f));
  }
  // Registers a member function as the callback. The first template  parameter
  // is the class containing the member function, the second is the address of
  // the member function. The data pointer is used to store the address of the
  // class instance and is therefore not available to the user.
  template <class C, void (C::*M)(Args...)>
  void
  set_func(C* obj) noexcept {
    set_func(
        [](Args... args, void* data) noexcept {
          auto obj = static_cast<C*>(data);
          (obj->*M)(args...);
        },
        static_cast<void*>(obj));
  }
  ...
};
}  // namespace lib
}  // namespace lely
#endif  // !LELY_LIB_OBJ_HPP_
Registering a C-style global (or static) function in C++ is similar to C:
void my_func(Args... args, void* data) noexcept;
void
set_func(Object* obj, void* data) {
  obj->set_func(&my_func, data);
}
The second form of set_func() allows registering a function object. The user
is responsible for lifetime of the object.
struct MyFunctionObject {
  void operator()(Args... args) noexcept;
};
void
set_func(Object* obj, MyFunctionObject* f) {
  obj->set_func(f);
}
The third form of set_func() allows member functions to be registered as
callbacks. Again, the user is responsible for the lifetime of the instance of
the class containing the member function.
class MyClass {
 public:
  void my_func(Args... args) noexcept;
};
void
set_func(Object* obj, MyClass* cls) {
  obj->set_func<MyClass, &MyClass::my_func>(cls);
}
It is also possible to register private methods as callbacks, but only from a function which has private access (i.e., a friend or another method).