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

Binder.h

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

File content as of revision 18:a0fde14b6c39:

/*  Binder
 *  Static function binding
 */
#ifndef BINDER_H
#define BINDER_H

#include "FuncPtr.h"


/** Static function binding
 */
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:
    /** Create an unbound Binder
     */
    Binder() {}

    /** Create a Binder, binding arguments to a function
     */
    Binder(FuncPtr<R(B0, B1, B2, B3)> 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)> 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)>(obj, method), b0, b1, b2, b3);
    }

    /** Call the bound function
     */
    R call() {
        return _func(_b0, _b1, _b2, _b3);
    }

    /** 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), B0, B1, B2, B3>*>(func)
                ->call();
    }

private:
    FuncPtr<R(B0, B1, B2, B3)> _func;
    B0 _b0; B1 _b1; B2 _b2; B3 _b3;
};

/** Static function binding
 */
template <typename R, typename B0, typename B1, typename B2, typename A0>
class Binder<R(B0, B1, B2, A0), B0, B1, B2> {
public:
    /** Create an unbound Binder
     */
    Binder() {}

    /** Create a Binder, binding arguments to a function
     */
    Binder(FuncPtr<R(B0, B1, B2, A0)> 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)> 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)>(obj, method), b0, b1, b2);
    }

    /** Call the bound function
     */
    R call(A0 a0) {
        return _func(_b0, _b1, _b2, 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, A0), B0, B1, B2>*>(func)
                ->call(a0);
    }

private:
    FuncPtr<R(B0, B1, B2, A0)> _func;
    B0 _b0; B1 _b1; B2 _b2; 
};

/** Static function binding
 */
template <typename R, typename B0, typename B1, typename A0, typename A1>
class Binder<R(B0, B1, A0, A1), B0, B1> {
public:
    /** Create an unbound Binder
     */
    Binder() {}

    /** Create a Binder, binding arguments to a function
     */
    Binder(FuncPtr<R(B0, B1, A0, A1)> 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)> 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)>(obj, method), b0, b1);
    }

    /** Call the bound function
     */
    R call(A0 a0, A1 a1) {
        return _func(_b0, _b1, 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, A0, A1), B0, B1>*>(func)
                ->call(a0, a1);
    }

private:
    FuncPtr<R(B0, B1, A0, A1)> _func;
    B0 _b0; B1 _b1;
};

/** Static function binding
 */
template <typename R, typename B0, typename A0, typename A1, typename A2>
class Binder<R(B0, A0, A1, A2), B0> {
public:
    /** Create an unbound Binder
     */
    Binder() {}

    /** Create a Binder, binding arguments to a function
     */
    Binder(FuncPtr<R(B0, A0, A1, A2)> 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)> 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)>(obj, method), b0);
    }

    /** Call the bound function
     */
    R call(A0 a0, A1 a1, A2 a2) {
        return _func(_b0, 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, A0, A1, A2), B0>*>(func)
                ->call(a0, a1, a2);
    }

private:
    FuncPtr<R(B0, A0, A1, A2)> _func;
    B0 _b0;
};

/** Static function binding
 */
template <typename R, typename B0, typename B1, typename B2>
class Binder<R(B0, B1, B2), B0, B1, B2> {
public:
    /** Create an unbound Binder
     */
    Binder() {}

    /** Create a Binder, binding arguments to a function
     */
    Binder(FuncPtr<R(B0, B1, B2)> 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)> 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)>(obj, method), b0, b1, b2);
    }

    /** Call the bound function
     */
    R call() {
        return _func(_b0, _b1, _b2);
    }

    /** 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), B0, B1, B2>*>(func)
                ->call();
    }

private:
    FuncPtr<R(B0, B1, B2)> _func;
    B0 _b0; B1 _b1; B2 _b2;
};

/** Static function binding
 */
template <typename R, typename B0, typename B1, typename A0>
class Binder<R(B0, B1, A0), B0, B1> {
public:
    /** Create an unbound Binder
     */
    Binder() {}

    /** Create a Binder, binding arguments to a function
     */
    Binder(FuncPtr<R(B0, B1, A0)> 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)> 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)>(obj, method), b0, b1);
    }

    /** Call the bound function
     */
    R call(A0 a0) {
        return _func(_b0, _b1, 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, A0), B0, B1>*>(func)
                ->call(a0);
    }

private:
    FuncPtr<R(B0, B1, A0)> _func;
    B0 _b0; B1 _b1;
};

/** Static function binding
 */
template <typename R, typename B0, typename A0, typename A1>
class Binder<R(B0, A0, A1), B0> {
public:
    /** Create an unbound Binder
     */
    Binder() {}

    /** Create a Binder, binding arguments to a function
     */
    Binder(FuncPtr<R(B0, A0, A1)> 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)> 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)>(obj, method), b0);
    }

    /** Call the bound function
     */
    R call(A0 a0, A1 a1) {
        return _func(_b0, 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, A0, A1), B0>*>(func)
                ->call(a0, a1);
    }

private:
    FuncPtr<R(B0, A0, A1)> _func;
    B0 _b0;
};

/** Static function binding
 */
template <typename R, typename B0, typename B1>
class Binder<R(B0, B1), B0, B1> {
public:
    /** Create an unbound Binder
     */
    Binder() {}

    /** Create a Binder, binding arguments to a function
     */
    Binder(FuncPtr<R(B0, B1)> 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)> 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)>(obj, method), b0, b1);
    }

    /** Call the bound function
     */
    R call() {
        return _func(_b0, _b1);
    }

    /** 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), B0, B1>*>(func)
                ->call();
    }

private:
    FuncPtr<R(B0, B1)> _func;
    B0 _b0; B1 _b1;
};

/** Static function binding
 */
template <typename R, typename B0, typename A0>
class Binder<R(B0, A0), B0> {
public:
    /** Create an unbound Binder
     */
    Binder() {}

    /** Create a Binder, binding arguments to a function
     */
    Binder(FuncPtr<R(B0, A0)> 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)> 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)>(obj, method), b0);
    }

    /** Call the bound function
     */
    R call(A0 a0) {
        return _func(_b0, 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, A0), B0>*>(func)
                ->call(a0);
    }

private:
    FuncPtr<R(B0, A0)> _func;
    B0 _b0;
};

/** Static function binding
 */
template <typename R, typename B0>
class Binder<R(B0), B0> {
public:
    /** Create an unbound Binder
     */
    Binder() {}

    /** Create a Binder, binding arguments to a function
     */
    Binder(FuncPtr<R(B0)> 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)> 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)>(obj, method), b0);
    }

    /** Call the bound function
     */
    R call() {
        return _func(_b0);
    }

    /** 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), B0>*>(func)
                ->call();
    }

private:
    FuncPtr<R(B0)> _func;
    B0 _b0;
};


#endif