Boost logo

Boost :

Subject: [boost] Determining interest in Delegates submission
From: Jared McKee (jared.mckee_at_[hidden])
Date: 2011-09-07 22:48:58


I would like to determine interest in a possible library submission.

I have written some code which converts a member function and object pointer
combination to a free function for use in C style callbacks. It has some
limitations which I will describe shortly.

The basic idea is to be able to convert:

R (B::*)(T0,T1,…) and B*

to

R (*)(T0,T1,…)

Here's an example usage:

class foo {
       int x;
       int test(int v) {return x + v;}
};

foo* a = new foo;
a->x = 3;
int (*f)(int) = delegate(a, &foo::inc);
cout << f(4) << endl; // outputs "7"

When I first attempted this I used a technique where I allocated some
executable memory in the heap and dynamically created a free function to
call the member function for the instance. It was fun attempting that but,
as you can imagine, as soon as I used the optimizer flags on my compiler I
would get segment faults :)

My second approach was to use templates and the Boost Preprocessor library
to create appropriate static arrays of pointers to free functions matching
the required signatures and then hand those pointers out each time the
delegate() function is called. The two downsides to this are: you can only
call delegate() for a certain function signature a limited number of times,
and it adds a lot of potentially unused code to your executable.

Here's the code (I've stripped out error checking for the sake of
illustration):

#include <boost/preprocessor.hpp>

#ifndef _delegate_h_
#define _delegate_h_

#define MAX_DELEGATES 256

#define DELEGATE_PARAMS 0
#include "delegate_template.hpp"
#undef DELEGATE_PARAMS

#define DELEGATE_PARAMS 1
#include "delegate_template.hpp"
#undef DELEGATE_PARAMS

// …

#endif

// delegate_template.hpp

#define DELEGATE_STORE BOOST_PP_CAT(DELEGATE_STORE,**DELEGATE_PARAMS)

template <class B, class R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS,
class T) >
struct DELEGATE_STORE {
 typedef B* objectPointer;
 typedef R (B::*memberFunction)( BOOST_PP_ENUM_PARAMS(DELEGATE_**PARAMS, T)
);
 typedef R (*freeFunction)( BOOST_PP_ENUM_PARAMS(DELEGATE_**PARAMS, T) );

 static int delegateCount;
 static int delegateMax;
 static objectPointer delegateObjectPointer[MAX_**DELEGATES];
 static memberFunction delegateMemberFunction[MAX_**DELEGATES];

 template <int i>
 static R func( BOOST_PP_ENUM_BINARY_PARAMS(**DELEGATE_PARAMS, T, v) ) {
    return (delegateObjectPointer[i]->***delegateMemberFunction[i])(
BOOST_PP_ENUM_PARAMS(DELEGATE_**PARAMS, v) );
 }

 static const freeFunction delegateFreeFunction[MAX_**DELEGATES];

 static freeFunction getDelegate(objectPointer o, memberFunction m) {
    int delegateIndex = delegateCount++;
    delegateObjectPointer[**delegateIndex] = o;
    delegateMemberFunction[**delegateIndex] = m;
    return delegateFreeFunction[**delegateIndex];
 }
};

template <class B, class R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS,
class T) >
int DELEGATE_STORE<B,R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS, T)
>::delegateCount = 0;

template <class B, class R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS,
class T) >
int DELEGATE_STORE<B,R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS, T)
>::delegateMax = MAX_DELEGATES;

template <class B, class R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS,
class T) >
typename DELEGATE_STORE<B,R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS,
T) >::memberFunction
DELEGATE_STORE<B,R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS, T)

> ::delegateMemberFunction[MAX_**DELEGATES] = {0};
>

template <class B, class R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS,
class T) >
typename DELEGATE_STORE<B,R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS,
T) >::objectPointer
DELEGATE_STORE<B,R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS, T)

> ::delegateObjectPointer[MAX_**DELEGATES] = {0};
>

#define FUNC_POINTER(z, n, params) &DELEGATE_STORE<B,R
BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS, T) >::template func< n >,

template <class B, class R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS,
class T) >
const typename DELEGATE_STORE<B,R
BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS,
T) >::freeFunction
DELEGATE_STORE<B,R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS, T)

> ::delegateFreeFunction[MAX_**DELEGATES] = {
>
 BOOST_PP_REPEAT(MAX_DELEGATES, FUNC_POINTER,)
};

template <class B, class R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS,
class T) >
R (*delegate( B* b, R (B::*f)( BOOST_PP_ENUM_PARAMS(DELEGATE_**PARAMS, T) )
))( BOOST_PP_ENUM_PARAMS(DELEGATE_**PARAMS, T) ) {
 return DELEGATE_STORE<B,R BOOST_PP_ENUM_TRAILING_PARAMS(**DELEGATE_PARAMS,
T) >::getDelegate(b, f);
}

// end

Thankyou very much if you managed to read all the way to here!

By the way, this is my first active participation in any open source project
:)

Jared


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk