6

I have a probably embarassingly simple problem: pass and call a member function in a class. I know I want to use BOOST bind (and or function), but I haven't really grasped the concept to it yet.

The following code compiles and executes with problem. But when I want to change the "f3" function to a non-static class function, then the fun begins:

#include <iostream>
#include <inttypes.h> 
#include <boost/bind.hpp>
#include <boost/function.hpp>

class Test
{
public:
  void f1();
private:
  void f2(void (*callfunc)(uint32_t));
  static void f3(uint32_t x);
};

void Test::f1(){
  f2(f3);
}

void Test::f2(void (*callfunc)(uint32_t)){
  (*callfunc)(42);
}

void Test::f3(uint32_t x){
  std::cout << "x: " << x << std::endl;
}

int main(int argc, char ** argv)
{
  Test ct;
  ct.f1();
  return 0;
}

Now, after changing

static void f3(uint32_t x);

to

void f3(uint32_t x);

the compiler isn't happy and tells me "error: no matching function for call to 'Test::f2()'"

Having read through a number of SO posts regarding boost::bind and boost::function, I think I need to change the definition of f2() and how f1() calls f2() giving f3() as target to call, but apart from that ... about every combination of boost::bind and boost function I tried miserably fails to compile.

How do I need to write this? As a bonus question: are there any simple introductory reads on boost::bind and boost::function? The BOOST docs did not really help me there.

B.

BaCh
  • 625
  • 2
  • 5
  • 17

2 Answers2

8

boost::function is a template class, that takes a function signature. You can also use function0, function1, etc.

boost::function< void(uint32_t) >

defines a "callable" that looks like a function, i.e. it takes a single parameter of type uint32_t and returns void.

The appropriate numbered template is function1< void, uint32_t >. These always indicate the return type first, then the parameters in order.

boost::bind is a very special function that deduces the arguments you pass into it and creates a functor for you.

It will not create a void(uint32_t) for you, it will create something that has the pattern of one.

Therefore change your signature to:

void f2(boost::function<void(uint32_t)>);

Then you can call it like this:

f2( boost::bind( &Test::f3, this, _1 ) );

Note the strange _1 is a "placeholder" telling boost::bind where it needs to put in the parameter, in this case the uint32_t

CashCow
  • 30,981
  • 5
  • 61
  • 92
5

First, I 'll explain the reason that removing the static gives you a compilation error:

Take a look at this signature:

void (*callfunc)(uint32_t)

This is a pointer to free function that takes an uint32_t and returns void. When f3 is declared inside Test as

void f3(uint32_t x);

then f3 is a member function of class Test that takes an uint32_t and returns void. Therefore, there is no f3 that matches the type of the argument that f2 is expecting.

As for how boost::function and boost::bind can be used to provide a solution:

void Test::f1(){
    boost::function<void (uint32_t)> f = boost::bind(&Test::f3, this, _1);
    f2(f);
}

Update:

Finally, regarding a tutorial: I found this useful when learning about functors (which is what boost::function is and boost::bind returns) in the past. It doesn't mention boost specifically, but once you understand what exactly is going on in a lower level you will find using boost a breeze.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • @CashCow: Yeah, just caught it a few mins ago since I didn't compile this. – Jon Mar 09 '11 at 11:56
  • If I could I'd also accept your answer as it has the link to the functor introduction. CashCow's answer was a tad more complete though with showing the signature of f2() (which was clear enough for me from your answer, but maybe not for others). Anyway, thank you very much for the answer and the link. – BaCh Mar 09 '11 at 13:17
  • @BaCh: No worries. I didn't touch the signature of `f2` on purpose, but if another answer looks better to you then you should absolutely accept it. I wouldn't mind an upvote though ;) – Jon Mar 09 '11 at 13:22