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);

Files at this revision

API Documentation at this revision

Comitter:
Christopher Haster
Date:
Sun Apr 17 23:38:04 2016 -0500
Parent:
17:079c5ad807fb
Commit message:
Increase to 5 args

Changed in this revision

Binder.h Show annotated file Show diff for this revision Revisions of this file
Chainer.h Show annotated file Show diff for this revision Revisions of this file
Composer.h Show annotated file Show diff for this revision Revisions of this file
FuncPtr.h Show annotated file Show diff for this revision Revisions of this file
diff -r 079c5ad807fb -r a0fde14b6c39 Binder.h
--- a/Binder.h	Wed Apr 20 02:43:14 2016 -0500
+++ b/Binder.h	Sun Apr 17 23:38:04 2016 -0500
@@ -9,11 +9,346 @@
 
 /** Static function binding
  */
-template <typename F, typename B0=void, typename B1=void, typename B2=void, typename B3=void>
+template <typename F, typename B0=void, typename B1=void, typename B2=void, typename B3=void, typename B4=void>
 class Binder;
 
 /** Static function binding
  */
+template <typename R, typename B0, typename B1, typename B2, typename B3, typename B4>
+class Binder<R(B0, B1, B2, B3, B4), B0, B1, B2, B3, B4> {
+public:
+    /** Create an unbound Binder
+     */
+    Binder() {}
+
+    /** Create a Binder, binding arguments to a function
+     */
+    Binder(FuncPtr<R(B0, B1, B2, B3, B4)> func, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) {
+        attach(func, b0, b1, b2, b3, b4);
+    }
+
+    /** Create a Binder, binding arguments to a method
+     */
+    template <typename T, typename M>
+    Binder(T *obj, M method, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) {
+        attach(obj, method, b0, b1, b2, b3, b4);
+    }
+
+    /** Bind arguments to a function
+     */
+    void attach(FuncPtr<R(B0, B1, B2, B3, B4)> func, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) {
+        _func.attach(func);
+        _b0 = b0; _b1 = b1; _b2 = b2; _b3 = b3; _b4 = b4;
+    }
+
+    /** Bind arguments to a method
+     */
+    template <typename T, typename M>
+    void attach(T *obj, M method, B0 b0, B1 b1, B2 b2, B3 b3, B4 b4) {
+        attach(FuncPtr<R(B0, B1, B2, B3, B4)>(obj, method), b0, b1, b2, b3, b4);
+    }
+
+    /** Call the bound function
+     */
+    R call() {
+        return _func(_b0, _b1, _b2, _b3, _b4);
+    }
+
+    /** Call the bound function
+     */
+    R operator()() {
+        return call();
+    }
+
+    /** Test if function has been bound
+     */
+    operator bool() const {
+        return _func;
+    }
+
+    /** Static thunk for passing as C-style function
+     *  @param func Binder to call passed as void pointer
+     */
+    static R thunk(void *func) {
+        return static_cast<Binder<R(B0, B1, B2, B3, B4), B0, B1, B2, B3, B4>*>(func)
+                ->call();
+    }
+
+private:
+    FuncPtr<R(B0, B1, B2, B3, B4)> _func;
+    B0 _b0; B1 _b1; B2 _b2; B3 _b3; B4 _b4;
+};
+
+/** Static function binding
+ */
+template <typename R, typename B0, typename B1, typename B2, typename B3, typename A0>
+class Binder<R(B0, B1, B2, B3, A0), B0, B1, B2, B3> {
+public:
+    /** Create an unbound Binder
+     */
+    Binder() {}
+
+    /** Create a Binder, binding arguments to a function
+     */
+    Binder(FuncPtr<R(B0, B1, B2, B3, A0)> func, B0 b0, B1 b1, B2 b2, B3 b3) {
+        attach(func, b0, b1, b2, b3);
+    }
+
+    /** Create a Binder, binding arguments to a method
+     */
+    template <typename T, typename M>
+    Binder(T *obj, M method, B0 b0, B1 b1, B2 b2, B3 b3) {
+        attach(obj, method, b0, b1, b2, b3);
+    }
+
+    /** Bind arguments to a function
+     */
+    void attach(FuncPtr<R(B0, B1, B2, B3, A0)> func, B0 b0, B1 b1, B2 b2, B3 b3) {
+        _func.attach(func);
+        _b0 = b0; _b1 = b1; _b2 = b2; _b3 = b3;
+    }
+
+    /** Bind arguments to a method
+     */
+    template <typename T, typename M>
+    void attach(T *obj, M method, B0 b0, B1 b1, B2 b2, B3 b3) {
+        attach(FuncPtr<R(B0, B1, B2, B3, A0)>(obj, method), b0, b1, b2, b3);
+    }
+
+    /** Call the bound function
+     */
+    R call(A0 a0) {
+        return _func(_b0, _b1, _b2, _b3, a0);
+    }
+
+    /** Call the bound function
+     */
+    R operator()(A0 a0) {
+        return call(a0);
+    }
+
+    /** Test if function has been bound
+     */
+    operator bool() const {
+        return _func;
+    }
+
+    /** Static thunk for passing as C-style function
+     *  @param func Binder to call passed as void pointer
+     */
+    static R thunk(void *func, A0 a0) {
+        return static_cast<Binder<R(B0, B1, B2, B3, A0), B0, B1, B2, B3>*>(func)
+                ->call(a0);
+    }
+
+private:
+    FuncPtr<R(B0, B1, B2, B3, A0)> _func;
+    B0 _b0; B1 _b1; B2 _b2; B3 _b3;
+};
+
+/** Static function binding
+ */
+template <typename R, typename B0, typename B1, typename B2, typename A0, typename A1>
+class Binder<R(B0, B1, B2, A0, A1), B0, B1, B2> {
+public:
+    /** Create an unbound Binder
+     */
+    Binder() {}
+
+    /** Create a Binder, binding arguments to a function
+     */
+    Binder(FuncPtr<R(B0, B1, B2, A0, A1)> func, B0 b0, B1 b1, B2 b2) {
+        attach(func, b0, b1, b2);
+    }
+
+    /** Create a Binder, binding arguments to a method
+     */
+    template <typename T, typename M>
+    Binder(T *obj, M method, B0 b0, B1 b1, B2 b2) {
+        attach(obj, method, b0, b1, b2);
+    }
+
+    /** Bind arguments to a function
+     */
+    void attach(FuncPtr<R(B0, B1, B2, A0, A1)> func, B0 b0, B1 b1, B2 b2) {
+        _func.attach(func);
+        _b0 = b0; _b1 = b1; _b2 = b2;
+    }
+
+    /** Bind arguments to a method
+     */
+    template <typename T, typename M>
+    void attach(T *obj, M method, B0 b0, B1 b1, B2 b2) {
+        attach(FuncPtr<R(B0, B1, B2, A0, A1)>(obj, method), b0, b1, b2);
+    }
+
+    /** Call the bound function
+     */
+    R call(A0 a0, A1 a1) {
+        return _func(_b0, _b1, _b2, a0, a1);
+    }
+
+    /** Call the bound function
+     */
+    R operator()(A0 a0, A1 a1) {
+        return call(a0, a1);
+    }
+
+    /** Test if function has been bound
+     */
+    operator bool() const {
+        return _func;
+    }
+
+    /** Static thunk for passing as C-style function
+     *  @param func Binder to call passed as void pointer
+     */
+    static R thunk(void *func, A0 a0, A1 a1) {
+        return static_cast<Binder<R(B0, B1, B2, A0, A1), B0, B1, B2>*>(func)
+                ->call(a0, a1);
+    }
+
+private:
+    FuncPtr<R(B0, B1, B2, A0, A1)> _func;
+    B0 _b0; B1 _b1; B2 _b2; 
+};
+
+/** Static function binding
+ */
+template <typename R, typename B0, typename B1, typename A0, typename A1, typename A2>
+class Binder<R(B0, B1, A0, A1, A2), B0, B1> {
+public:
+    /** Create an unbound Binder
+     */
+    Binder() {}
+
+    /** Create a Binder, binding arguments to a function
+     */
+    Binder(FuncPtr<R(B0, B1, A0, A1, A2)> func, B0 b0, B1 b1) {
+        attach(func, b0, b1);
+    }
+
+    /** Create a Binder, binding arguments to a method
+     */
+    template <typename T, typename M>
+    Binder(T *obj, M method, B0 b0, B1 b1) {
+        attach(obj, method, b0, b1);
+    }
+
+    /** Bind arguments to a function
+     */
+    void attach(FuncPtr<R(B0, B1, A0, A1, A2)> func, B0 b0, B1 b1) {
+        _func.attach(func);
+        _b0 = b0; _b1 = b1;
+    }
+
+    /** Bind arguments to a method
+     */
+    template <typename T, typename M>
+    void attach(T *obj, M method, B0 b0, B1 b1) {
+        attach(FuncPtr<R(B0, B1, A0, A1, A2)>(obj, method), b0, b1);
+    }
+
+    /** Call the bound function
+     */
+    R call(A0 a0, A1 a1, A2 a2) {
+        return _func(_b0, _b1, a0, a1, a2);
+    }
+
+    /** Call the bound function
+     */
+    R operator()(A0 a0, A1 a1, A2 a2) {
+        return call(a0, a1, a2);
+    }
+
+    /** Test if function has been bound
+     */
+    operator bool() const {
+        return _func;
+    }
+
+    /** Static thunk for passing as C-style function
+     *  @param func Binder to call passed as void pointer
+     */
+    static R thunk(void *func, A0 a0, A1 a1, A2 a2) {
+        return static_cast<Binder<R(B0, B1, A0, A1, A2), B0, B1>*>(func)
+                ->call(a0, a1, a2);
+    }
+
+private:
+    FuncPtr<R(B0, B1, A0, A1, A2)> _func;
+    B0 _b0; B1 _b1;
+};
+
+/** Static function binding
+ */
+template <typename R, typename B0, typename A0, typename A1, typename A2, typename A3>
+class Binder<R(B0, A0, A1, A2, A3), B0> {
+public:
+    /** Create an unbound Binder
+     */
+    Binder() {}
+
+    /** Create a Binder, binding arguments to a function
+     */
+    Binder(FuncPtr<R(B0, A0, A1, A2, A3)> func, B0 b0) {
+        attach(func, b0);
+    }
+
+    /** Create a Binder, binding arguments to a method
+     */
+    template <typename T, typename M>
+    Binder(T *obj, M method, B0 b0) {
+        attach(obj, method, b0);
+    }
+
+    /** Bind arguments to a function
+     */
+    void attach(FuncPtr<R(B0, A0, A1, A2, A3)> func, B0 b0) {
+        _func.attach(func);
+        _b0 = b0;
+    }
+
+    /** Bind arguments to a method
+     */
+    template <typename T, typename M>
+    void attach(T *obj, M method, B0 b0) {
+        attach(FuncPtr<R(B0, A0, A1, A2, A3)>(obj, method), b0);
+    }
+
+    /** Call the bound function
+     */
+    R call(A0 a0, A1 a1, A2 a2, A3 a3) {
+        return _func(_b0, a0, a1, a2, a3);
+    }
+
+    /** Call the bound function
+     */
+    R operator()(A0 a0, A1 a1, A2 a2, A3 a3) {
+        return call(a0, a1, a2, a3);
+    }
+
+    /** Test if function has been bound
+     */
+    operator bool() const {
+        return _func;
+    }
+
+    /** Static thunk for passing as C-style function
+     *  @param func Binder to call passed as void pointer
+     */
+    static R thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3) {
+        return static_cast<Binder<R(B0, A0, A1, A2, A3), B0>*>(func)
+                ->call(a0, a1, a2, a3);
+    }
+
+private:
+    FuncPtr<R(B0, A0, A1, A2, A3)> _func;
+    B0 _b0;
+};
+
+/** Static function binding
+ */
 template <typename R, typename B0, typename B1, typename B2, typename B3>
 class Binder<R(B0, B1, B2, B3), B0, B1, B2, B3> {
 public:
diff -r 079c5ad807fb -r a0fde14b6c39 Chainer.h
--- a/Chainer.h	Wed Apr 20 02:43:14 2016 -0500
+++ b/Chainer.h	Sun Apr 17 23:38:04 2016 -0500
@@ -14,6 +14,76 @@
 
 /** Static function composition
  */
+template <typename A0, typename A1, typename A2, typename A3, typename A4, int N>
+class Chainer<void(A0, A1, A2, A3, A4), N> {
+public:
+    /** Access a function in the chain
+     */
+    FuncPtr<void(A0, A1, A2, A3, A4)> &operator[](int i) {
+        return _funcs[i];
+    }
+
+    /** Attach a function to the chain
+     */
+    bool attach(FuncPtr<void(A0, A1, A2, A3, A4)> func) {
+        for (int i = 0; i < N; i++) {
+            if (!_funcs[i]) {
+                _funcs[i].attach(func);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /** Attach a function to the chain
+     */
+    template <typename T, typename M>
+    bool attach(T *obj, M method) {
+        return attach(FuncPtr<void(A0, A1, A2, A3, A4)>(obj, method));
+    }
+
+    /** Call each function in the chain
+     */
+    void call(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+        for (int i = 0; i < N; i++) {
+            if (_funcs[i]) {
+                _funcs[i](a0, a1, a2, a3, a4);
+            }
+        }
+    }
+
+    /** Call each function in the chain
+     */
+    void operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+        return call(a0, a1, a2, a3, a4);
+    }
+
+    /** Test if any functions have been attached
+     */
+    operator bool() const {
+        for (int i = 0; i < N; i++) {
+            if (_funcs[i]) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** Static thunk for passing as C-style function
+     *  @param func Chainer to call passed as void pointer
+     */
+    static void thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+        return static_cast<Chainer<void(A0, A1, A2, A3, A4), N>*>(func)
+                ->call(a0, a1, a2, a3, a4);
+    }
+
+private:
+    FuncPtr<void(A0, A1, A2, A3, A4)> _funcs[N];
+};
+
+/** Static function composition
+ */
 template <typename A0, typename A1, typename A2, typename A3, int N>
 class Chainer<void(A0, A1, A2, A3), N> {
 public:
diff -r 079c5ad807fb -r a0fde14b6c39 Composer.h
--- a/Composer.h	Wed Apr 20 02:43:14 2016 -0500
+++ b/Composer.h	Sun Apr 17 23:38:04 2016 -0500
@@ -14,6 +14,102 @@
 
 /** Static function composition
  */
+template <typename R, typename B0, typename A0, typename A1, typename A2, typename A3, typename A4>
+class Composer<R(B0), B0(A0, A1, A2, A3, A4)> {
+public:
+    /** Create an uncomposed Composer
+     */
+    Composer() {}
+
+    /** Create a Composer, composing two functions
+     */
+    Composer(FuncPtr<R(B0)> f, FuncPtr<B0(A0, A1, A2, A3, A4)> g) {
+        attach(f, g);
+    }
+
+    /** Create a Composer, composing functions and methods
+     */
+    template <typename FT, typename FM>
+    Composer(FT *fobj, FM fmethod, FuncPtr<B0(A0, A1, A2, A3, A4)> g) {
+        attach(fobj, fmethod, g);
+    }
+
+    /** Create a Composer, composing functions and methods
+     */
+    template <typename GT, typename GM>
+    Composer(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) {
+        attach(f, gobj, gmethod);
+    }
+
+    /** Create a Composer, composing functions and methods
+     */
+    template <typename FT, typename FM, typename GT, typename GM>
+    Composer(FT *fobj, FM fmethod, GT *gobj, GM gmethod) {
+        attach(fobj, fmethod, gobj, gmethod);
+    }
+
+    /** Compose two functions
+     */
+    void attach(FuncPtr<R(B0)> f, FuncPtr<B0(A0, A1, A2, A3, A4)> g) {
+        _f.attach(f);
+        _g.attach(g);
+    }
+
+    /** Compose functions and methods
+     */
+    template <typename FT, typename FM>
+    void attach(FT *fobj, FM fmethod, FuncPtr<B0(A0, A1, A2, A3, A4)> g) {
+        attach(FuncPtr<R(B0)>(fobj, fmethod), g);
+    }
+
+    /** Compose functions and methods
+     */
+    template <typename GT, typename GM>
+    void attach(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) {
+        attach(f, FuncPtr<B0(A0, A1, A2, A3, A4)>(gobj, gmethod));
+    }
+
+    /** Compose functions and methods
+     */
+    template <typename FT, typename FM, typename GT, typename GM>
+    void attach(FT *fobj, FM fmethod, GT *gobj, GM gmethod) {
+        attach(FuncPtr<R(B0)>(fobj, fmethod),
+               FuncPtr<B0(A0, A1, A2, A3, A4)>(gobj, gmethod));
+    }
+
+    /** Call the composed functions
+     */
+    R call(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+        return _f(_g(a0, a1, a2, a3, a4));
+    }
+
+    /** Call the composed functions
+     */
+    R operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+        return call(a0, a1, a2, a3, a4);
+    }
+
+    /** Test if functions have been composed
+     */
+    operator bool() const {
+        return _f && _g;
+    }
+
+    /** Static thunk for passing as C-style function
+     *  @param func Composer to call passed as void pointer
+     */
+    static R thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+        return static_cast<Composer<R(B0), B0(A0, A1, A2, A3, A4)>*>(func)
+                ->call(a0, a1, a2, a3, a4);
+    }
+
+private:
+    FuncPtr<R(B0)> _f;
+    FuncPtr<B0(A0, A1, A2, A3, A4)> _g;
+};
+
+/** Static function composition
+ */
 template <typename R, typename B0, typename A0, typename A1, typename A2, typename A3>
 class Composer<R(B0), B0(A0, A1, A2, A3)> {
 public:
@@ -37,7 +133,7 @@
     /** Create a Composer, composing functions and methods
      */
     template <typename GT, typename GM>
-    Composer(FuncPtr<B0(A0, A1, A2, A3)> f, GT *gobj, GM gmethod) {
+    Composer(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) {
         attach(f, gobj, gmethod);
     }
 
@@ -133,7 +229,7 @@
     /** Create a Composer, composing functions and methods
      */
     template <typename GT, typename GM>
-    Composer(FuncPtr<B0(A0, A1, A2)> f, GT *gobj, GM gmethod) {
+    Composer(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) {
         attach(f, gobj, gmethod);
     }
 
@@ -229,7 +325,7 @@
     /** Create a Composer, composing functions and methods
      */
     template <typename GT, typename GM>
-    Composer(FuncPtr<B0(A0, A1)> f, GT *gobj, GM gmethod) {
+    Composer(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) {
         attach(f, gobj, gmethod);
     }
 
@@ -325,7 +421,7 @@
     /** Create a Composer, composing functions and methods
      */
     template <typename GT, typename GM>
-    Composer(FuncPtr<B0(A0)> f, GT *gobj, GM gmethod) {
+    Composer(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) {
         attach(f, gobj, gmethod);
     }
 
@@ -421,7 +517,7 @@
     /** Create a Composer, composing functions and methods
      */
     template <typename GT, typename GM>
-    Composer(FuncPtr<B0()> f, GT *gobj, GM gmethod) {
+    Composer(FuncPtr<R(B0)> f, GT *gobj, GM gmethod) {
         attach(f, gobj, gmethod);
     }
 
diff -r 079c5ad807fb -r a0fde14b6c39 FuncPtr.h
--- a/FuncPtr.h	Wed Apr 20 02:43:14 2016 -0500
+++ b/FuncPtr.h	Sun Apr 17 23:38:04 2016 -0500
@@ -17,6 +17,160 @@
 
 /** Flexible templated function class
  */
+template <typename R, typename A0, typename A1, typename A2, typename A3, typename A4>
+class FuncPtr<R(A0, A1, A2, A3, A4)> {
+public:
+    /** Create a FuncPtr with a static function
+     *  @param func Static function to attach
+     */
+    FuncPtr(R (*func)(A0, A1, A2, A3, A4) = 0) {
+        attach(func);
+    }
+
+    /** Create a FuncPtr with a static function and bound pointer
+     *  @param obj  Pointer to object to bind to function
+     *  @param func Static function to attach
+     */
+    template<typename T>
+    FuncPtr(T *obj, R (*func)(T*, A0, A1, A2, A3, A4)) {
+        attach(obj, func);
+    }
+
+    /** Create a FuncPtr with a method
+     *  @param obj  Pointer to object to invoke method on
+     *  @param func Method to attach
+     */
+    template<typename T>
+    FuncPtr(T *obj, R (T::*func)(A0, A1, A2, A3, A4)) {
+        attach(obj, func);
+    }
+
+    /** Create a FuncPtr with a function object
+     *  @param func Function object to attach
+     */
+    template<typename T>
+    FuncPtr(T *obj) {
+        attach(obj, &T::operator());
+    }
+
+    /** Create a FuncPtr with another FuncPtr
+     *  @param func FuncPtr to attach
+     */
+    FuncPtr(const FuncPtr<R(A0, A1, A2, A3, A4)> &func) {
+        attach(func);
+    }
+
+    /** Attach a static function
+     *  @param func Static function to attach
+     */
+    void attach(R (*func)(A0, A1, A2, A3, A4)) {
+        memcpy(&_func, &func, sizeof func);
+        _thunk = func ? &FuncPtr::_staticthunk : 0;
+    }
+
+    /** Attach a static function with a bound pointer
+     *  @param obj  Pointer to object to bind to function
+     *  @param func Static function to attach
+     */
+    template <typename T>
+    void attach(T *obj, R (*func)(T*, A0, A1, A2, A3, A4)) {
+        _obj = static_cast<void*>(obj);
+        memcpy(&_func, &func, sizeof func);
+        _thunk = &FuncPtr::_boundthunk<T>;
+    }
+
+    /** Attach a method
+     *  @param obj  Pointer to object to invoke method on
+     *  @param func Method to attach
+     */
+    template<typename T>
+    void attach(T *obj, R (T::*func)(A0, A1, A2, A3, A4)) {
+        _obj = static_cast<void*>(obj);
+        memcpy(&_func, &func, sizeof func);
+        _thunk = &FuncPtr::_methodthunk<T>;
+    }
+
+    /** Attach a function object
+     *  @param func Function object to attach
+     */
+    template<typename T>
+    void attach(T *func) {
+        attach(func, &T::operator());
+    }
+
+    /** Attach a FuncPtr
+     *  @param func The FuncPtr to attach
+     */
+    void attach(const FuncPtr<R(A0, A1, A2, A3, A4)> &func) {
+        _obj = func._obj;
+        memcpy(&_func, &func._func, sizeof _func);
+        _thunk = func._thunk;
+    }
+
+    /** Call the attached function
+     */
+    R call(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+        return _thunk(_obj, &_func, a0, a1, a2, a3, a4);
+    }
+
+    /** Call the attached function
+     */
+    R operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+        return call(a0, a1, a2, a3, a4);
+    }
+
+    /** Test if function has been attached
+     */
+    operator bool() const {
+        return _thunk;
+    }
+
+    /** Static thunk for passing as C-style function
+     *  @param func FuncPtr to call passed as void pointer
+     */
+    static R thunk(void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+        return static_cast<FuncPtr<R(A0, A1, A2, A3, A4)>*>(func)
+                ->call(a0, a1, a2, a3, a4);
+    }
+
+private:
+    // Internal thunks for various function types
+    static R _staticthunk(void*, void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+        return (*reinterpret_cast<R (**)(A0, A1, A2, A3, A4)>(func))
+                (a0, a1, a2, a3, a4);
+    }
+
+    template<typename T>
+    static R _boundthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+        return (*reinterpret_cast<R (**)(T*, A0, A1, A2, A3, A4)>(func))
+                (static_cast<T*>(obj), a0, a1, a2, a3, a4);
+    }
+
+    template<typename T>
+    static R _methodthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) {
+        return (static_cast<T*>(obj)->*
+                (*reinterpret_cast<R (T::**)(A0, A1, A2, A3, A4)>(func)))
+                (a0, a1, a2, a3, a4);
+    }
+
+    // Stored as pointer to function and pointer to optional object
+    // Function pointer is stored as union of possible function types
+    // to garuntee proper size and alignment
+    struct _class;
+    union {
+        void (*_staticfunc)();
+        void (*_boundfunc)(_class *);
+        void (_class::*_methodfunc)();
+    } _func;
+
+    void *_obj;
+
+    // Thunk registered on attach to dispatch calls
+    R (*_thunk)(void*, void*, A0, A1, A2, A3, A4); 
+};
+
+/** Flexible templated function class
+ */
 template <typename R, typename A0, typename A1, typename A2, typename A3>
 class FuncPtr<R(A0, A1, A2, A3)> {
 public: