views:

99

answers:

2

Is there a simple way to forward to a member function with a matching function signature?

typedef std::tr1::function<int(int,int,int,int)> TheFn;
class C
{
    int MemberFn(int,int,int,int) { return 0; }

    TheFn getFn() { 
        //is there a simpler way to write the following line?
        return [this](int a,int b,int c,int d){ return this->MemberFn(a,b,c,d); };
    } 
};
A: 

It may be possible to make something out of Boost::Lambda, but in reality, I'd suggest not, except that you may find it easier to use a trailing return type than explicitly typedef. In addition, as far as I know, when you capture this, as a special case, then the lambda becomes a member lambda, as it were, and you don't need the explicit this->.

DeadMG
+1  A: 

Have you tried bind?

// C++0x update
struct test {
   void f( int, int, int, int );
};
int main()
{
   std::function<void (int,int,int,int)> fn;
   test t;
   fn = std::bind( &t::f, &t, 
           std::placeholders::_1, 
           std::placeholders::_2, 
           std::placeholders::_3, 
           std::placeholders::_4 );
   fn( 1, 2, 3, 4 ); // t.f( 1, 2, 3, 4 )
}

I have left the full qualification of all elements, but std::placeholders applied so many times don't really help readability... I guess a using std::placeholders would not hurt at all:

using std::placeholders;
fn = std::bind( &t::f, &t, _1, _2, _3, _4 );

EDIT: To make it closer to the question code, so that it is clearer that this has the exact same functionality that the original code:

typedef std::function<int(int,int,int,int)> TheFn;
class C {
   int MemberFn( int, int, int, int ) { return 0; }
public:
   int MemberFn2(int,int,int,int) { return 2; }
   TheFn getFn() {
      using std::placeholders;
      return std::bind( &C::MemberFn, this, _1, _2, _3, _4 );
   }
};
int main() {
   C instance;
   TheFn fn1 = instance.getFn();
   std::cout << fn1( 1, 2, 3, 4 ) << std::endl; // 0

   using std::placeholders;
   TheFn fn2 = std::bind( &C::MemberFn2, &instance, _1, _2, _3, _4 );
   std::cout << fn2( 1, 2, 3, 4 ) << std::endl;
}

As you can see in both cases you are doing the same. I have used private and public methods for the example to show that when you bind, the member method access level is checked at the place of bind, not at the place of call. So even if MemberFn is private within the class you can call it through the binded functor. If the member is public, you can actually bind from outside of the class.

David Rodríguez - dribeas