Flexible templated function class and related utilities that avoid dynamic memory allocation without limiting functionality

Dependents:   SimpleHTTPExample

FuncPtr provides a flexible templated function class and related utilities while avoiding dynamic memory allocation and avoiding limited functionality.

FuncPtr provides an intuitive template interface:

FuncPtr<void(const char *)> func(puts);
func("hello!\n"); // prints hello!


Several function types are supported by FuncPtr:

// Simple C functions
void func();
FuncPtr<void()> fp(func);

// C++ Methods
struct Thing { void func(); };
Thing thing;
FuncPtr<void()> fp(&thing, &Thing::func);

// C functions with context
void func(Thing *);
FuncPtr<void()> fp(&thing, func);

// Function objects
struct Thing { void operator()(); };
Thing thing;
FuncPtr<void()> fp(&thing);


There is no dynamic memory allocation, managing memory is placed entirely on the user. More advanced function manipulation can be accomplished with statically allocated classes:

// Function binding
Binder<void(const char *), const char *> bind(putc, "hi!");
bind(); // prints hi!

// Function composition
Composer<int(const char *), const char *(int)> comp(puts, itoa);
comp(10); // prints 10

// Function chaining
Chainer<void(const char *), 2> chain;
chain.attach(puts);
chain.attach(puts);
chain("hi!\n"); // prints hi! twice


FuncPtr allows easy support of a large range of function types in C++ APIs with very few lines of code:

class Thing {
public:
    // The following two methods are sufficient for supporting 
    // every supported function type
    void attach(FuncPtr<void()> func) {
        _func.attach(func);
    }

    template<typename T, typename M>
    void attach(T *obj, M method) {
        attach(FuncPtr<void()>(obj, method));
    }

private:
    FuncPtr<void()> _func;
}


Additionally, FuncPtrs have several utilities for easy integration with C APIs:

// C style callbacks
void register_callback(void (*callback)(void *), void *data);

register_callback(&FuncPtr<void()>::thunk, &func);

// C style functions without context
void register_callback(void (*callback)());

Thunker thunk(func);
register_callback(thunk);

// mbed style callbacks
void register_callback(T *obj, void (T::*M)());

register_callback(&func, &FuncPtr<void()>::call);

Revision:
15:0c3d1c4a050b
Parent:
14:79be4e700cc9
Child:
18:a0fde14b6c39
--- a/Chainer.h	Sun Apr 17 21:25:00 2016 -0500
+++ b/Chainer.h	Sun Apr 17 22:01:07 2016 -0500
@@ -9,13 +9,13 @@
 
 /** Static function chaining
  */
-template <int N, typename F>
+template <typename F, int N>
 class Chainer;
 
 /** Static function composition
  */
-template <int N, typename A0, typename A1, typename A2, typename A3>
-class Chainer<N, void(A0, A1, A2, A3)> {
+template <typename A0, typename A1, typename A2, typename A3, int N>
+class Chainer<void(A0, A1, A2, A3), N> {
 public:
     /** Access a function in the chain
      */
@@ -74,7 +74,7 @@
      *  @param func Chainer to call passed as void pointer
      */
     static void thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3) {
-        return static_cast<Chainer<N, void(A0, A1, A2, A3)>*>(func)
+        return static_cast<Chainer<void(A0, A1, A2, A3), N>*>(func)
                 ->call(a0, a1, a2, a3);
     }
 
@@ -84,8 +84,8 @@
 
 /** Static function composition
  */
-template <int N, typename A0, typename A1, typename A2>
-class Chainer<N, void(A0, A1, A2)> {
+template <typename A0, typename A1, typename A2, int N>
+class Chainer<void(A0, A1, A2), N> {
 public:
     /** Access a function in the chain
      */
@@ -144,7 +144,7 @@
      *  @param func Chainer to call passed as void pointer
      */
     static void thunk(void *func, A0 a0, A1 a1, A2 a2) {
-        return static_cast<Chainer<N, void(A0, A1, A2)>*>(func)
+        return static_cast<Chainer<void(A0, A1, A2), N>*>(func)
                 ->call(a0, a1, a2);
     }
 
@@ -154,8 +154,8 @@
 
 /** Static function composition
  */
-template <int N, typename A0, typename A1>
-class Chainer<N, void(A0, A1)> {
+template <typename A0, typename A1, int N>
+class Chainer<void(A0, A1), N> {
 public:
     /** Access a function in the chain
      */
@@ -214,7 +214,7 @@
      *  @param func Chainer to call passed as void pointer
      */
     static void thunk(void *func, A0 a0, A1 a1) {
-        return static_cast<Chainer<N, void(A0, A1)>*>(func)
+        return static_cast<Chainer<void(A0, A1), N>*>(func)
                 ->call(a0, a1);
     }
 
@@ -224,8 +224,8 @@
 
 /** Static function composition
  */
-template <int N, typename A0>
-class Chainer<N, void(A0)> {
+template <typename A0, int N>
+class Chainer<void(A0), N> {
 public:
     /** Access a function in the chain
      */
@@ -284,7 +284,7 @@
      *  @param func Chainer to call passed as void pointer
      */
     static void thunk(void *func, A0 a0) {
-        return static_cast<Chainer<N, void(A0)>*>(func)
+        return static_cast<Chainer<void(A0), N>*>(func)
                 ->call(a0);
     }
 
@@ -295,7 +295,7 @@
 /** Static function composition
  */
 template <int N>
-class Chainer<N, void()> {
+class Chainer<void(), N> {
 public:
     /** Access a function in the chain
      */
@@ -354,7 +354,7 @@
      *  @param func Chainer to call passed as void pointer
      */
     static void thunk(void *func) {
-        return static_cast<Chainer<N, void()>*>(func)
+        return static_cast<Chainer<void(), N>*>(func)
                 ->call();
     }