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