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

Reply via email to