Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Bound Member Function Pointer

19 views
Skip to first unread message

Marco Manfredini

unread,
May 31, 2003, 10:26:52 AM5/31/03
to
Hello.

For some reason (I want to pass function pointers to certain libraries)
I'd like to convert a member function into a real function pointer. gcc
has an extension which can do that, but for portability I came up with
this solution:

// overload this for each arity
template<class C, class R, class A>
struct bmfhelpertype
{
typedef R (*fn_type)(C*, A);
template<R (C::*X)(A)>
static fn_type getfun()
{
struct anon
{
static R fn(C* c, A a) { return (c->*X)(a); }
};
return anon::fn;
}
};

// overload this for each arity
template<class C, class R, class A>
bmfhelpertype<C,R,A> bmfhelper(R (C::*mf)(A))
{
return bmfhelpertype<C,R,A>();
}

// use it
class A
{
public:
int a_member(int k)
{
return k*k;
}
};

int main()
{
int (*fn)(A*,int)=bmfhelper(&A::a_member).getfun<&A::a_member>();
A a;
int r=fn(&a, 3); // sets r to 9
}

The duplication of &A::a_member as a function *and* a template parameter
looks awkward to me, but I can't figure out a way to avoid this. I
somehow need that bmfhelper function call to make the template value
parameter possible. Has anybody a better idea?

Nice weekend to you all.

Marco

--
The text above is a result of a bug in my newsreader and I take no
responsibility for this text appearing in my post.


[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Ulrich Eckhardt

unread,
Jun 2, 2003, 5:23:54 AM6/2/03
to
Marco Manfredini wrote:
[snipped conversion from 'R O::*(...)' to 'R (*)(O*,...)']

> The duplication of &A::a_member as a function *and* a template parameter
> looks awkward to me, but I can't figure out a way to avoid this. I
> somehow need that bmfhelper function call to make the template value
> parameter possible. Has anybody a better idea?

You might want to take a look at sigC++ (libsigc.sf.net). It pretty much
does the same in order to construct its signals internally.

cheers
Ulrich Eckhardt

--
Questions ?
see C++-FAQ Lite: http://parashift.com/c++-faq-lite/ first !

Terje Slettebø

unread,
Jun 2, 2003, 1:25:34 PM6/2/03
to
"Marco Manfredini" <ma...@technoboredom.net> wrote in message
news:2045294.t...@technoboredom.net...

>
> For some reason (I want to pass function pointers to certain
libraries)
> I'd like to convert a member function into a real function pointer.
gcc
> has an extension which can do that, but for portability I came up with
> this solution:

<snip>

> // use it
> class A
> {
> public:
> int a_member(int k)
> {
> return k*k;
> }
> };
>
> int main()
> {
> int (*fn)(A*,int)=bmfhelper(&A::a_member).getfun<&A::a_member>();
> A a;
> int r=fn(&a, 3); // sets r to 9
> }

boost::function fits this situation like a glove: :)

#include <boost/function.hpp>

int main()
{
boost::function<int (A*,int)> fn=&A::a_member;

// The rest the same

A a;
int r=fn(&a, 3); // sets r to 9
}

It can be found at (http://www.boost.org/doc/html/function.html).


Regards,

Terje

Marco Manfredini

unread,
Jun 2, 2003, 2:30:10 PM6/2/03
to
Ulrich Eckhardt wrote:

> Marco Manfredini wrote:
> [snipped conversion from 'R O::*(...)' to 'R (*)(O*,...)']
> > The duplication of &A::a_member as a function *and* a template
> > parameter looks awkward to me, but I can't figure out a way to
> > avoid this. I somehow need that bmfhelper function call to make the
> > template value parameter possible. Has anybody a better idea?
>
> You might want to take a look at sigC++ (libsigc.sf.net). It pretty
> much does the same in order to construct its signals internally.
>

Not quite. sigc++ uses the "hide everything behind a structure that can
later be used like a function from C++" approach. What I do is to
generate a *real* function pointer during compile time which can later
be used on an object (as an additional paramter). This is a generally
useful thing, because the function pointer can be passed to any library
that understands the c calling convention (including the ffcall
library, which has the tremendously interesting trampoline() function).

Greetings,

Marco
--
The text above is a result of a bug in my newsreader and I take no
responsibility for this text appearing in my post.

Marco Manfredini

unread,
Jun 3, 2003, 3:01:20 PM6/3/03
to
Terje Slettebų wrote:

>
> boost::function fits this situation like a glove: :)

on a claw :(

I'm acquainted with boost.function, but I'd like to have (1) a real
function pointer, not a construct, without (2) the necessity to mention
the member pointer *twice* in the expression. To reiterate: Any attempt
to construct a free function pointer out of a constant member pointer
comes out to some expression of the kind
a_function(memberpointer).another_function<memberpointer>() and I can't
get behind that. It's like C++ isn't hi-fi enough to do that.

Greetings
Marco

P.S.
http://www.boost.org/doc/html/function.misc.html#id2885974

discusses the two concepts.

--
The text above is a result of a bug in my newsreader and I take no
responsibility for this text appearing in my post.

Hiram Berry

unread,
Jun 4, 2003, 7:55:44 AM6/4/03
to
"Marco Manfredini" <ma...@technoboredom.net> wrote in message
news:7587659.x...@technoboredom.net...

> Terje Slettebř wrote:
> >
> > boost::function fits this situation like a glove: :)
>
> on a claw :(
>
> I'm acquainted with boost.function, but I'd like to have (1) a real
> function pointer, not a construct,
> without (2) the necessity to mention
> the member pointer *twice* in the expression. To reiterate: Any attempt
> to construct a free function pointer out of a constant member pointer
> comes out to some expression of the kind
> a_function(memberpointer).another_function<memberpointer>() and I can't
> get behind that. It's like C++ isn't hi-fi enough to do that.
>
> Greetings
> Marco

Marco,

Using your "templated static" idiom, I doubt that it's possible to avoid
repeating the member pointer argument. Since the class itself is not
specialized on the pointer to member, that information must be passed in a
different way; two function calls repeating the argument seem inevitable.
The code you wrote in your initial post looks to me to be the most direct
way to accomplish that. It does achieve your real goal of returning a real
function pointer, so I don't think the stylistic redundancy should bother
you too terribly much.

Faced with this requirement (want to return a function pointer) I'd use a
more primitive syntax and make the member-pointer as a nontype template arg.
It's more verbose, but does make the static function nontemplate so its
address can be returned implicitly by a conversion operator. Something
like:

template<class C,class R,class A,R (C::*pmf)(A)>
class Binder{
static R fxn(C *c,A a){ return (c->*pmf)(a);}
public:
typedef R (*ftype)(C *,A);
operator ftype(){ return fxn;}
};

Then say for an example class:

struct Example{
double x;
Example(double x):x(x){}
double f(int a){ return a/x;}
};

it can be used:

Example i(2.5);
typedef Binder<Example,double,int,&Example::f> Bound;
Bound::ftype g=Bound();
cout<<g(&i,3)<<'\n';

This returns a real function pointer, and technically doesn't repeat the
"&Example::f", but the verbosity of the template args is just as bad. While
you were able to use a "type deduction" function to simplify the interface,
unfortunately with this method it isn't possible to do (without generating
more new arguments than are saved, anyway) because seemingly one can't use
template function argument type deduction to easily deduce the value of a
nontype template arg. After several attempts to pass the pmf wrapped as a
classtype so it could be deduced by the interface function with no good
results, I tried a different tack, to rewrite the "Binder" class somewhat
like a traits class so the interface function could be written. It still
needs 2 repeated args, but at least they're in the same argument list:

template<class C,class R,class A,class T>
class Binder2{
static T pmf;
static R fxn(C *c,A a){ return (c->*pmf)(a);}
public:
typedef R (*ftype)(C *,A);
operator ftype(){ return fxn;}
Binder2(T pmf){ Binder2<C,R,A,T>::pmf=pmf;}
};
template<class C,class R,class A,class T>
T Binder2<C,R,A,T>::pmf;

template<class C,class R,class A,class T>
Binder2<C,R,A,T> Deduce2(R (C::*)(A),T pmf){
return Binder2<C,R,A,T>(pmf);
}
// usage:
double (*h)(Example *,int)=Deduce2(&Example::f,&Example::f);
cout<<h(&i,4)<<'\n';

Then it seemed to me that one might use another round of type deduction
trickery to unify the arguments of Deduce2 to get the desired interface:

template<class C,class R,class A>
Binder2<C,R,A,R (C::*)(A)> Deduce(R (C::*pmf)(A)){
return Deduce2(pmf,pmf);
}
// usage:
double (*k)(Example *,int)=Deduce(&Example::f);
cout<<k(&i,7)<<'\n';

This worked for me, though I'm not positive there aren't hidden UB gotchas
somewhere. Hopefully this was the solution you were looking for.

Regards,

Hiram Berry

Terje Slettebø

unread,
Jun 5, 2003, 9:46:18 AM6/5/03
to
"Hiram Berry" <burn...@burningbridges.com> wrote in message
news:bbjq4m$f...@dispatch.concentric.net...

> "Marco Manfredini" <ma...@technoboredom.net> wrote in message
> news:7587659.x...@technoboredom.net...
>

I thought about something like this, too, but a problem with this
approach is that you may get several member functions mapped to the same
static function, if they have the same signature. That's because the
template signature template<class C, class R, class A, class T> (T=type
of member function) doesn't distinguish between member functions with
the same signature.

The following example shows the problem:

#include <iostream>

struct Example
{
double x;
Example(double x):x(x){}

double f(int a){ return a+x;}
double g(int a){ return -a-x;}
};

template<class C,class R,class A,class T>
class Binder2
{
static T pmf;
static R fxn(C *c,A a){ return (c->*pmf)(a);}

public:
typedef R (*ftype)(C *,A);
operator ftype(){ return fxn;}
Binder2(T pmf){ Binder2<C,R,A,T>::pmf=pmf;}
};

template<class C,class R,class A,class T>
T Binder2<C,R,A,T>::pmf;

template<class C,class R,class A,class T>
Binder2<C,R,A,T> Deduce2(R (C::*)(A),T pmf)
{
return Binder2<C,R,A,T>(pmf);
}

int main()
{
Example i(1);
double (*f)(Example *,int)=Deduce2(&Example::f,&Example::f);
double (*g)(Example *,int)=Deduce2(&Example::g,&Example::g);
std::cout << f(&i,3) << '\n' << g(&i,3) << '\n';
}

This prints "-4", "-4" (rather than "4", "-4"), showing that both f and
g in main() use the same member function, Example::g.


Regards,

Terje

Terje Slettebø

unread,
Jun 5, 2003, 9:54:57 AM6/5/03
to
"Hiram Berry" <burn...@burningbridges.com> wrote in message
news:bbjq4m$f...@dispatch.concentric.net...
> "Marco Manfredini" <ma...@technoboredom.net> wrote in message
> news:7587659.x...@technoboredom.net...
>
> template<class C,class R,class A,R (C::*pmf)(A)>
> class Binder{
> static R fxn(C *c,A a){ return (c->*pmf)(a);}
> public:
> typedef R (*ftype)(C *,A);
> operator ftype(){ return fxn;}
> };
>
> Then say for an example class:
>
> struct Example{
> double x;
> Example(double x):x(x){}
> double f(int a){ return a/x;}
> };
>
> it can be used:
>
> Example i(2.5);
> typedef Binder<Example,double,int,&Example::f> Bound;
> Bound::ftype g=Bound();
> cout<<g(&i,3)<<'\n';

This works, but the current version doesn't readily extend to functions
of arbitrary arity (since you can't overload class templates).

The following is a version of this which does extend to arbitrary arity,
and which also resembles boost::function in use:

#include <iostream>

struct Example
{
double x;
Example(double x):x(x){}

double f(int a){ return a+x;}
double g(int a){ return -a-x;}
};

template<class C,class R,class A,R (C::*pmf)(A)>


class Binder
{
static R fxn(C *c,A a){ return (c->*pmf)(a);}

public:
typedef R (*ftype)(C *,A);
operator ftype(){ return fxn;}
};

template<class T>
class function;

template<class R, class C, class A>
class function<R (C *, A)>
{
public:
template<R (C::*pmf)(A)>
class mem_fn : public Binder<C,R,A,pmf> {};
};

int main()
{
Example i(1);
// Binder<Example,double,int,&Example::f> f;
function<double (Example *, int)>::mem_fn<&Example::f> f;
function<double (Example *, int)>::mem_fn<&Example::g> g;


std::cout << f(&i,3) << '\n' << g(&i,3) << '\n';
}

For comparison, using boost::function, the above could be written as:

boost::function<double (Example *, int)> f(&Example::f);

Also note that in templates, if it uses dependent types, the above
version needs the "::template" syntax:

function<R (C *, T)>::template mem_fn<&C::f> f;

With some imagination, it may be read as creating a function (pointer)
from a member function (pointer). :)

With both the first version above and this version, you at least avoid
having to repeat the member function pointer, as in the original
posting:

int (*fn)(A*,int)=bmfhelper(&A::a_member).getfun<&A::a_member>();


Regards,

Terje

Terje Slettebø

unread,
Jun 5, 2003, 10:03:31 AM6/5/03
to
I've got it! :)

Sorry for the multiple posts, but I came to think of another way, after
I sent the previous posting:

#include <iostream>
#include <boost/type_traits/function_traits.hpp>
#include <boost/type_traits/remove_pointer.hpp>

template<class C,class R,class A,R (C::*pmf)(A)>
class Binder
{
static R fxn(C *c,A a){ return (c->*pmf)(a);}

public:
typedef R (*ftype)(C *,A);
operator ftype(){ return fxn;}
};

template<class T>
struct mem_fn;

template<class R, class C, class A>

struct mem_fn<R (C*, A)>
{
typedef R (C::*type)(A);
};

template<class T,typename mem_fn<T>::type pmf>
struct function : Binder<
typename boost::remove_pointer<
typename boost::function_traits<T>::arg1_type
>::type,
typename boost::function_traits<T>::result_type,
typename boost::function_traits<T>::arg2_type,
pmf
> {};

struct Example
{
double x;
Example(double x):x(x){}

double f(int a){ return a+x;}
double g(int a){ return -a-x;}
};

// Use:

int main()
{
Example i(1);
function<double (Example *, int), &Example::f> f;
function<double (Example *, int), &Example::g> g;


std::cout << f(&i,3) << '\n' << g(&i,3) << '\n';
}

The "function" definition appears a little complicated, as partial
specialisation didn't work in this case. I tried the following:

template<class T,typename mem_fn<T>::type>
struct function;

template<class R, class C, class A, R (C::*pmf)(A)>
struct function<R (C*, A), R (C::*pmf)(A)> : Binder<C, R, A, pmf> {};

But it didn't work on Intel C++ 7.1 or MSVC 7.1, so I used the above,
instead.

In any case, it can now be used in practically the same way as
boost::function.

>Marco Manfredini:


>
> Any attempt
> to construct a free function pointer out of a constant member pointer
> comes out to some expression of the kind
> a_function(memberpointer).another_function<memberpointer>() and I
can't
> get behind that. It's like C++ isn't hi-fi enough to do that.

Oh, how I've been longing to say that, yes!, C++ _is_ hi-fi enough for
that. ;)


Regards,

Terje

0 new messages