Boost logo

Boost :

From: Dave Abrahams (abrahams_at_[hidden])
Date: 1999-12-10 00:20:22


This is a preliminary submission, with test program.

The family of template classes bound_fn are function objects which dispatch
through member function pointers. Unlike similar classes, though, a
bound_fn's type is determined solely by the type of its arguments and its
return type. Thus, member functions taking the same arguments on unrelated
classes can be called uniformly, and the pointers can even be assigned to
one another.

I have several concerns which I'd like some help with:

1. bound_fn, the name. I hate abbreviations, but more importantly, there are
too many varieties of these beasts, and I don't want to step on the
varieties I am not implementing by grabbing a name that's too general. For
example, you could have a bound function where the target class type *is*
part of the type. Maybe this could be done with specialization, so there's
no problem...

2. It seems like, to be truly useful, these should be extended to wrap any
function, including a non-member function. That would make this a family of
truly general function pointers. In this case, bound_fn is an even more
inappropriate name.

3. Perhaps something can be done to reduce the footprint and overhead of
these classes? I tried to get the member function pointer into the type
parameter list for the dispatcher as a value parameter, but either C++ or my
compiler (Metrowerks) wouldn't handle it, or I just reached the limits of my
template chops.

4. Obviously we'd need to extend this to 0 argument and 3+ argument
versions. Also probably an operator= for comparison would be in order.

-Dave

-------------- test.cpp ---------------

#include "bound_fn.hpp"

#include <iostream>
struct Result
{
     Result(int x) : x(x) {}
     int x;
};

struct Arg
{
     Arg() : x(3) {}
     int x;
};

struct C
{
     Result g1(Arg) { return Result(1); }
     void g2(char*) {}
     Result g3(const Arg&) { return Result(3); }
};

struct D
{
     Result g4(Arg) const { return Result(4); }
     Result g5(const Arg&) const { return Result(5); }
};

static int test()
{
     C x;
     using boost::bound_fn;

     bound_fn<void (*)(char*)> f2(&x, &C::g2);

     Arg a1;

     bound_fn<Result(*)(Arg)> f1(&x, &C::g1);
     std::cout << f1(a1).x << std::endl;

     bound_fn<Result(*)(Arg)> f3(&x, &C::g3);
     std::cout << f3(a1).x << std::endl;

     bound_fn<Result(*)(Arg)> f4(&x, &D::g4);
     std::cout << f4(a1).x << std::endl;

     bound_fn<Result(*)(Arg)> f5(&x, &D::g5);
     std::cout << f5(a1).x << std::endl;

     f4 = f1;
     std::cout << f4(a1).x << std::endl;

     return 0;
}

--------------- bound_fn.hpp -------------------

#include <functional>

namespace boost
{

template <class T>
struct const_ref
{
 typedef const T& type;
};

template <class T>
struct const_ref<const T&>
{
 typedef const T& type;
};

class Anonymous {};
typedef void (Anonymous::*anon_mf)();

template <class X>
struct dispatcher {};

template <class R, class C, class A>
struct dispatcher<R (C::*)(A)>
{
 static R go(void *p, anon_mf f, const_ref<A>::type arg)
 {
  typedef R (C::*PMF)(A);
  const PMF pmf = reinterpret_cast<PMF>(f);
  C* const c = reinterpret_cast<C*>(p);
  return (c->*pmf)(arg);
 }
};

template <class T>
struct bound_fn {};

template <class R, class A>
struct bound_fn<R (*)(A)> : public std::unary_function<A, R>
{
 typedef R (*dispatch_type)(void*, anon_mf f, const A& arg);

 template <class C, class PMF>
 bound_fn(C* target, PMF pmf)
  : m_target((void*)target),
    m_fn(reinterpret_cast<anon_mf>(pmf)),
    m_dispatch(dispatcher<PMF>::go)
 {}
 
 R operator()(const A& arg)
 {
  return m_dispatch(m_target, m_fn, arg);
 }
 
private:
 void *m_target;
 anon_mf m_fn;
 dispatch_type m_dispatch;
};

template <class R, class C, class A1, class A2>
struct dispatcher<R (C::*)(A1, A2)>
{
 static R go(void *p, anon_mf f, const_ref<A1>::type arg1,
const_ref<A2>::type arg2)
 {
  typedef R (C::*PMF)(A1, A2);
  const PMF pmf = reinterpret_cast<PMF>(f);
  C* const c = reinterpret_cast<C*>(p);
  return (c->*pmf)(arg1, arg2);
 }
};

template <class R, class A1, class A2>
struct bound_fn<R (*)(A1, A2)> : public std::binary_function<A1, A2, R>
{
 typedef R (*dispatch_type)(void*, anon_mf f, const A1& arg1, const A2&
arg2);

 template <class C, class PMF>
 bound_fn(C* target, PMF pmf)
  : m_target((void*)target),
    m_fn(reinterpret_cast<anon_mf>(pmf)),
    m_dispatch(dispatcher<PMF>::go)
 {}
 
 R operator()(const A1& arg1, const A2& arg2)
 {
  return m_dispatch(m_target, m_fn, arg1, arg2);
 }
 
private:
 void *m_target;
 anon_mf m_fn;
 dispatch_type m_dispatch;
};

}


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