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

FuncPtr.h

Committer:
Christopher Haster
Date:
2016-04-17
Revision:
18:a0fde14b6c39
Parent:
14:79be4e700cc9

File content as of revision 18:a0fde14b6c39:

/*  FuncPtr
 *
 *  Flexible templated function class that avoids dynamic memory
 *  allocation without limiting functionality
 */
#ifndef FUNCPTR_H
#define FUNCPTR_H

#include <string.h>
#include <stdint.h>


/** FuncPtr class based on template specialization
 */
template <typename F>
class FuncPtr;

/** 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:
    /** Create a FuncPtr with a static function
     *  @param func Static function to attach
     */
    FuncPtr(R (*func)(A0, A1, A2, A3) = 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)) {
        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)) {
        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)> &func) {
        attach(func);
    }

    /** Attach a static function
     *  @param func Static function to attach
     */
    void attach(R (*func)(A0, A1, A2, A3)) {
        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)) {
        _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)) {
        _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)> &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) {
        return _thunk(_obj, &_func, a0, a1, a2, a3);
    }

    /** Call the attached function
     */
    R operator()(A0 a0, A1 a1, A2 a2, A3 a3) {
        return call(a0, a1, a2, a3);
    }

    /** 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) {
        return static_cast<FuncPtr<R(A0, A1, A2, A3)>*>(func)
                ->call(a0, a1, a2, a3);
    }

private:
    // Internal thunks for various function types
    static R _staticthunk(void*, void *func, A0 a0, A1 a1, A2 a2, A3 a3) {
        return (*reinterpret_cast<R (**)(A0, A1, A2, A3)>(func))
                (a0, a1, a2, a3);
    }

    template<typename T>
    static R _boundthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2, A3 a3) {
        return (*reinterpret_cast<R (**)(T*, A0, A1, A2, A3)>(func))
                (static_cast<T*>(obj), a0, a1, a2, a3);
    }

    template<typename T>
    static R _methodthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2, A3 a3) {
        return (static_cast<T*>(obj)->*
                (*reinterpret_cast<R (T::**)(A0, A1, A2, A3)>(func)))
                (a0, a1, a2, a3);
    }

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

/** Flexible templated function class
 */
template <typename R, typename A0, typename A1, typename A2>
class FuncPtr<R(A0, A1, A2)> {
public:
    /** Create a FuncPtr with a static function
     *  @param func Static function to attach
     */
    FuncPtr(R (*func)(A0, A1, A2) = 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)) {
        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)) {
        attach(obj, func);
    }

    /** Create a FuncPtr with a function object
     *  @param func Function object to attach
     */
    template<typename T>
    FuncPtr(T *func) {
        attach(func, &T::operator());
    }

    /** Create a FuncPtr with another FuncPtr
     *  @param func FuncPtr to attach
     */
    FuncPtr(const FuncPtr<R(A0, A1, A2)> &func) {
        attach(func);
    }

    /** Attach a static function
     *  @param func Static function to attach
     */
    void attach(R (*func)(A0, A1, A2)) {
        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)) {
        _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)) {
        _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)> &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) {
        return _thunk(_obj, &_func, a0, a1, a2);
    }

    /** Call the attached function
     */
    R operator()(A0 a0, A1 a1, A2 a2) {
        return call(a0, a1, a2);
    }

    /** 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) {
        return static_cast<FuncPtr<R(A0, A1, A2)>*>(func)
                ->call(a0, a1, a2);
    }

private:
    // Internal thunks for various function types
    static R _staticthunk(void*, void *func, A0 a0, A1 a1, A2 a2) {
        return (*reinterpret_cast<R (**)(A0, A1, A2)>(func))
                (a0, a1, a2);
    }

    template<typename T>
    static R _boundthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2) {
        return (*reinterpret_cast<R (**)(T*, A0, A1, A2)>(func))
                (static_cast<T*>(obj), a0, a1, a2);
    }

    template<typename T>
    static R _methodthunk(void *obj, void *func, A0 a0, A1 a1, A2 a2) {
        return (static_cast<T*>(obj)->*
                (*reinterpret_cast<R (T::**)(A0, A1, A2)>(func)))
                (a0, a1, a2);
    }

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

/** Flexible templated function class
 */
template <typename R, typename A0, typename A1>
class FuncPtr<R(A0, A1)> {
public:
    /** Create a FuncPtr with a static function
     *  @param func Static function to attach
     */
    FuncPtr(R (*func)(A0, A1) = 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)) {
        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)) {
        attach(obj, func);
    }

    /** Create a FuncPtr with a function object
     *  @param func Function object to attach
     */
    template<typename T>
    FuncPtr(T *func) {
        attach(func, &T::operator());
    }

    /** Create a FuncPtr with another FuncPtr
     *  @param func FuncPtr to attach
     */
    FuncPtr(const FuncPtr<R(A0, A1)> &func) {
        attach(func);
    }

    /** Attach a static function
     *  @param func Static function to attach
     */
    void attach(R (*func)(A0, A1)) {
        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)) {
        _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)) {
        _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)> &func) {
        _obj = func._obj;
        memcpy(&_func, &func._func, sizeof _func);
        _thunk = func._thunk;
    }

    /** Call the attached function
     */
    R call(A0 a0, A1 a1) {
        return _thunk(_obj, &_func, a0, a1);
    }

    /** Call the attached function
     */
    R operator()(A0 a0, A1 a1) {
        return call(a0, a1);
    }

    /** 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) {
        return static_cast<FuncPtr<R(A0, A1)>*>(func)
                ->call(a0, a1);
    }

private:
    // Internal thunks for various function types
    static R _staticthunk(void*, void *func, A0 a0, A1 a1) {
        return (*reinterpret_cast<R (**)(A0, A1)>(func))
                (a0, a1);
    }

    template<typename T>
    static R _boundthunk(void *obj, void *func, A0 a0, A1 a1) {
        return (*reinterpret_cast<R (**)(T*, A0, A1)>(func))
                (static_cast<T*>(obj), a0, a1);
    }

    template<typename T>
    static R _methodthunk(void *obj, void *func, A0 a0, A1 a1) {
        return (static_cast<T*>(obj)->*
                (*reinterpret_cast<R (T::**)(A0, A1)>(func)))
                (a0, a1);
    }

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

/** Flexible templated function class
 */
template <typename R, typename A0>
class FuncPtr<R(A0)> {
public:
    /** Create a FuncPtr with a static function
     *  @param func Static function to attach
     */
    FuncPtr(R (*func)(A0) = 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)) {
        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)) {
        attach(obj, func);
    }

    /** Create a FuncPtr with a function object
     *  @param func Function object to attach
     */
    template<typename T>
    FuncPtr(T *func) {
        attach(func, &T::operator());
    }

    /** Create a FuncPtr with another FuncPtr
     *  @param func FuncPtr to attach
     */
    FuncPtr(const FuncPtr<R(A0)> &func) {
        attach(func);
    }

    /** Attach a static function
     *  @param func Static function to attach
     */
    void attach(R (*func)(A0)) {
        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)) {
        _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)) {
        _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)> &func) {
        _obj = func._obj;
        memcpy(&_func, &func._func, sizeof _func);
        _thunk = func._thunk;
    }

    /** Call the attached function
     */
    R call(A0 a0) {
        return _thunk(_obj, &_func, a0);
    }

    /** Call the attached function
     */
    R operator()(A0 a0) {
        return call(a0);
    }

    /** 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) {
        return static_cast<FuncPtr<R(A0)>*>(func)
                ->call(a0);
    }

private:
    // Internal thunks for various function types
    static R _staticthunk(void*, void *func, A0 a0) {
        return (*reinterpret_cast<R (**)(A0)>(func))
                (a0);
    }

    template<typename T>
    static R _boundthunk(void *obj, void *func, A0 a0) {
        return (*reinterpret_cast<R (**)(T*, A0)>(func))
                (static_cast<T*>(obj), a0);
    }

    template<typename T>
    static R _methodthunk(void *obj, void *func, A0 a0) {
        return (static_cast<T*>(obj)->*
                (*reinterpret_cast<R (T::**)(A0)>(func)))
                (a0);
    }

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

/** Flexible templated function class
 */
template <typename R>
class FuncPtr<R()> {
public:
    /** Create a FuncPtr with a static function
     *  @param func Static function to attach
     */
    FuncPtr(R (*func)() = 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*)) {
        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)()) {
        attach(obj, func);
    }

    /** Create a FuncPtr with a function object
     *  @param func Function object to attach
     */
    template<typename T>
    FuncPtr(T *func) {
        attach(func, &T::operator());
    }

    /** Create a FuncPtr with another FuncPtr
     *  @param func FuncPtr to attach
     */
    FuncPtr(const FuncPtr<R()> &func) {
        attach(func);
    }

    /** Attach a static function
     *  @param func Static function to attach
     */
    void attach(R (*func)()) {
        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*)) {
        _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)()) {
        _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()> &func) {
        _obj = func._obj;
        memcpy(&_func, &func._func, sizeof _func);
        _thunk = func._thunk;
    }

    /** Call the attached function
     */
    R call() {
        return _thunk(_obj, &_func);
    }

    /** Call the attached function
     */
    R operator()() {
        return call();
    }

    /** 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) {
        return static_cast<FuncPtr<R()>*>(func)
                ->call();
    }

private:
    // Internal thunks for various function types
    static R _staticthunk(void*, void *func) {
        return (*reinterpret_cast<R (**)()>(func))
                ();
    }

    template<typename T>
    static R _boundthunk(void *obj, void *func) {
        return (*reinterpret_cast<R (**)(T*)>(func))
                (static_cast<T*>(obj));
    }

    template<typename T>
    static R _methodthunk(void *obj, void *func) {
        return (static_cast<T*>(obj)->*
                (*reinterpret_cast<R (T::**)()>(func)))
                ();
    }

    // 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*); 
};


#endif