In this comp.lang.c++.moderated thread
(http://www.google.com/groups?selm=2045294.t6ppZr3Erj%40technoboredom.net),
there was the following request:
--- Start quote ---
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:
[...]
// 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?
--- End quote ---
I immediately thought of boost::function, and suggested that. Then you could
write it like this:
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
}
However, it turned out that this couldn't be used for OP, as a real function
pointer, not a function object, was needed. That's understandable, if you
want to pass it to libraries that take a function pointer (for example
callbacks).
After some experimentation, for Hiram Berry and I, in the thread, we finally
arrived at a way it could be done, which may be used in practically the same
way as boost::function. It can be used like this:
int main()
{
function_ptr<int (A*, int), &A::a_member> fn;
// The rest the same
A a;
int r=fn(&a, 3); // sets r to 9
}
It creates a function object, but it has an implicit conversion to a
function pointer of the specified type, which calls the member function,
using the given object and any parameters.
Could there be any interest in this? For cases where a function pointer,
rather than function object, is required.
I've attached a version that has been tested on Intel C++ 7.1 and g++ 3.2,
and it includes a test.
The current version handles from 0 to 2 parameters, but can be extended
arbitrarily. It should probably handle the same number of arguments as
boost::function. Alternatively, this capability might be incorporated into
boost::function, if possible.
For a comparison between function objects and function pointers, see
(http://www.boost.org/doc/html/function.misc.html).
Since the member function is called from the function, it still requires two
calls through function pointers, like boost::function. However, the pointer
itself only takes up the size of one pointer, and it may be used with
libraries requiring function pointers, as mentioned.
Feedback is welcome.
Regards,
Terje
#include <iostream>
namespace detail
{
///////////////////////////////////////////////////////////////////////////////
// function_ptr_baseN
///////////////////////////////////////////////////////////////////////////////
template<class R, class C, R (C::*pmf)()>
struct function_ptr_base0
{
public:
typedef R (*ftype)(C *);
operator ftype() { return f; }
private:
static R f(C *c) { return (c->*pmf)(); }
};
template<class R, class C, class A1, R (C::*pmf)(A1)>
struct function_ptr_base1
{
public:
typedef R (*ftype)(C *, A1);
operator ftype() { return f; }
private:
static R f(C *c, A1 a1) { return (c->*pmf)(a1); }
};
template<class R, class C, class A1, class A2, R (C::*pmf)(A1, A2)>
struct function_ptr_base2
{
public:
typedef R (*ftype)(C *, A1, A2);
operator ftype() { return f; }
private:
static R f(C *c, A1 a1, A2 a2) { return (c->*pmf)(a1, a2); }
};
///////////////////////////////////////////////////////////////////////////////
// function_ptr_impl
///////////////////////////////////////////////////////////////////////////////
template<class T>
struct function_ptr_impl;
template<class R, class C>
struct function_ptr_impl<R (C*)>
{
typedef R (C::*type)();
template<type pmf>
struct base : function_ptr_base0<R, C, pmf> {};
};
template<class R, class C, class A1>
struct function_ptr_impl<R (C*, A1)>
{
typedef R (C::*type)(A1);
template<type pmf>
struct base : function_ptr_base1<R, C, A1, pmf> {};
};
template<class R, class C, class A1, class A2>
struct function_ptr_impl<R (C*, A1, A2)>
{
typedef R (C::*type)(A1, A2);
template<type pmf>
struct base : function_ptr_base2<R, C, A1, A2, pmf> {};
};
} // namespace detail
///////////////////////////////////////////////////////////////////////////////
// function_ptr
///////////////////////////////////////////////////////////////////////////////
template<class T, typename detail::function_ptr_impl<T>::type pmf>
struct function_ptr : detail::function_ptr_impl<T>::base<pmf> {};
///////////////////////////////////////////////////////////////////////////////
// Test
///////////////////////////////////////////////////////////////////////////////
class test
{
public:
test(int v) : value(v) {}
int f1() { return value; }
int f2(int a) { return a+value; }
int f3(int a) { return -a-value; }
double f4(double a, double b) { return a+b; }
private:
int value;
};
int main()
{
test t(1);
function_ptr<int (test *), &test::f1> f1;
function_ptr<int (test *, int), &test::f2> f2;
function_ptr<int (test *, int), &test::f3> f3;
function_ptr<double (test *, double, double), &test::f4> f4;
std::cout << f1(&t) << '\n' // Prints "1"
<< f2(&t,3) << '\n' // Prints "4"
<< f3(&t, 3) << '\n' // Prints "-4"
<< f4(&t, 1.23, 2.34) << '\n'; // Prints "3.57"
std::cin.ignore();
}
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost