How Boost::Function and Boost::Bind Work

how boost::function and boost::bind work

boost::function allows anything with an operator() with the right signature to be bound as the parameter, and the result of your bind can be called with a parameter int, so it can be bound to function<void(int)>.

This is how it works (this description applies alike for std::function):

boost::bind(&klass::member, instance, 0, _1) returns an object like this

struct unspecified_type
{
... some members ...
return_type operator()(int i) const { return instance->*&klass::member(0, i);
}

where the return_type and int are inferred from the signature of klass::member, and the function pointer and bound parameter are in fact stored in the object, but that's not important

Now, boost::function doesn't do any type checking: It will take any object and any signature you provide in its template parameter, and create an object that's callable according to your signature and calls the object. If that's impossible, it's a compile error.

boost::function is actually an object like this:

template <class Sig>
class function
{
function_impl<Sig>* f;
public:
return_type operator()(argument_type arg0) const { return (*f)(arg0); }
};

where the return_type and argument_type are extracted from Sig, and f is dynamically allocated on the heap. That's needed to allow completely unrelated objects with different sizes bind to boost::function.

function_impl is just an abstract class

template <class Sig>
class function_impl
{
public:
virtual return_type operator()(argument_type arg0) const=0;
};

The class that does all the work, is a concrete class derived from boost::function. There is one for each type of object you assign to boost::function

template <class Sig, class Object>
class function_impl_concrete : public function_impl<Sig>
{
Object o
public:
virtual return_type operator()(argument_type arg0) const=0 { return o(arg0); }
};

That means in your case, the assignment to boost function:

  1. instantiates a type function_impl_concrete<void(int), unspecified_type> (that's compile time, of course)
  2. creates a new object of that type on the heap
  3. assigns this object to the f member of boost::function

When you call the function object, it calls the virtual function of its implementation object, which will direct the call to your original function.

DISCLAIMER: Note that the names in this explanation are deliberately made up. Any resemblance to real persons or characters ... you know it. The purpose was to illustrate the principles.

How to use boost bind with a member function

Use the following instead:

boost::function<void (int)> f2( boost::bind( &myclass::fun2, this, _1 ) );

This forwards the first parameter passed to the function object to the function using place-holders - you have to tell Boost.Bind how to handle the parameters. With your expression it would try to interpret it as a member function taking no arguments.

See e.g. here or here for common usage patterns.

Note that VC8s cl.exe regularly crashes on Boost.Bind misuses - if in doubt use a test-case with gcc and you will probably get good hints like the template parameters Bind-internals were instantiated with if you read through the output.

How to use boost::bind to bind a member-function to ANY object

Many subtle tweaks, most simplifications:

Live On Coliru (c++03)

#include "boost/function.hpp" 
#include "boost/bind.hpp"
#include <vector>
#include <iostream>

class A
{
public:
A() {}

void func1(int i) const { std::cout << __PRETTY_FUNCTION__ << "(" << i << ")\n"; }
void func2(const std::string& s) const { std::cout << __PRETTY_FUNCTION__ << "(" << s << ")\n"; }

static void dispatch(const std::vector<A>& vect, boost::function<void(A const&)> const& func)
{
for ( std::vector<A>::const_iterator iter = vect.begin();
iter != vect.end();
++iter )
{
func(*iter);
}
}
};

int main()
{
std::vector<A> vect(3);

A::dispatch(vect, boost::bind(&A::func1, _1, 3));
A::dispatch(vect, boost::bind(&A::func2, _1, "hello"));
}

Notes

  • Use boost::function<void(A const&)> because you dereference const iterators
  • Use A::dispatch(vect, boost::bind(&A::func1, _1, 3));
  • Mark func1 and func2 const

    void func1(int i) const;
    void func2(std::string const& i) const;

Output:

void a::func1(int) const(3)
void a::func1(int) const(3)
void a::func1(int) const(3)
void a::func2(const std::string &) const(hello)
void a::func2(const std::string &) const(hello)
void a::func2(const std::string &) const(hello)

How to correctly bind a member function with boost::bind

Issue is you pass a pointer to a boost::function - you need to dereference first:

void Callbackcaller(boost::function<void(const T &)> *Callback_fn)  {
...
(*Callback_fn)(loc_tmp); //pipeline.hpp[96, 18]
};

Boost bind and boost function, storing functions with arguments in a vector and then executing them

your Task type wants an argument, it should have been boost::function0<void>. When you bind an argument, the returned (bound) callable object is of arity 0, not 1.

Also, to bind an argument you supply it to the call to boost::bind, the _1 etc are for arguments that are left unbound, not what you want here.

Something like (untested):

typedef boost::function0<void> Task;

Vector<Task> mScheduledTasks;
int MyArg = 5;

void SomeTask(void* arg)
{
// ....
}

void AddSomeTasks()
{
// nevermind that MyArg is globally accessible
for (int i = 0; i<5; i++)
mScheduledTasks.push_back(boost::bind(&SomeTask, (void*)&MyArg));
}

void ExecuteTask()
{
Task task = mScheduledTasks.front();
task();
}

Boost function and boost bind: Bind the return value?

If what you want is a nullary function that returns void but assigns a value to _myDouble with the result of foo() before doing so, then you cannot do this easily with just Boost.Bind. However, Boost has another library specifically catered to this sort of thing -- Boost.Phoenix:

#include <iostream>
#include <vector>
#include <boost/function.hpp>
#include <boost/phoenix/phoenix.hpp>

struct MyClass
{
MyClass() : _myVector(), _myInt(), _myDouble() { }
void setMyInt(int i);
void bar();
void execute();

private:
double foo(int const a) { return a * 2.; }

std::vector<boost::function<void()> > _myVector;
int _myInt;
double _myDouble;
};

void MyClass::setMyInt(int const i)
{
_myInt = i;
}

void MyClass::bar()
{
using boost::phoenix::bind;

_myVector.push_back(
bind(&MyClass::_myDouble, this) =
bind(&MyClass::foo, this, bind(&MyClass::_myInt, this))
);
}

void MyClass::execute()
{
if (_myVector.empty())
return;

_myVector.back()();
double const returnval = _myDouble;
std::cout << returnval << '\n';
}

int main()
{
MyClass mc;
mc.bar();

mc.setMyInt(21);
mc.execute(); // prints 42
mc.setMyInt(3);
mc.execute(); // prints 6 (using the same bound function!)
// i.e., bar has still only been called once and
// _myVector still contains only a single element;
// only mc._myInt was modified
}

boost::bind & boost::function with partial args

Just skip that argument.

   boost::function<void(int my_number)> functionWithSavedArgs
= boost::bind(&myPrinter, someText);

This binds only the first argument.

If you wanted to bind only the second one, you would need a placeholder:

   boost::function<void(int my_number)> functionWithSavedArgs
= boost::bind(&myPrinter, _1, someNumber);

Clarification on the use of `boost::bind` and `this`

boost::asio::placeholders::error is just like using boost::placeholders::_1 with boost::bind, and when you pass a bind expression containing that to an asio completion handler function, the function will invoke your handler with the boost::system::error_code result from the operation it performed, thus allowing your handler access to the error code.

In your second example, the boost::function signature for the following bind expression

boost::bind(
&someHandle,
ptr,
boost::asio::placeholders::error
)

is

boost::function<void(boost::system::error_code const&)>

To get your code to compile, change the statusPing() member function to

void statusPing(boost::function<void(boost::system::error_code const&)> f){
// Do work.
boost::system::error_code err;
f(err); // Call handle
}

Using boost:bind to bind a std::function

Your binding should be modified as follow:

void start_receive()
{
_socket.async_receive_from(
boost::asio::buffer( _buffer ),
_remote_endpoint,
boost::bind(
udp_server::_rx_handler,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,
42
)
);
}

You change _rx_handler from void (udp_server::*)(const boost::system::error_code&, std::size_t bytes_rx, int); to std::function<void(const boost::system::error_code&, std::size_t bytes_rx, int)>

So you no longer have to bind to an instance to udp_server.

boost::bind() binds extra arguments?

This is by design, unbound parameters (e.g. 1.0) passed when invoking the bind-expression are just ignored.

boost::function<void(const double&)> f = boost::bind(&MyClass::f, &c);
bar(f);

would do nicely for explicit assignment of the bind expression.

Update to the comment:

Remember, two guidelines:

  • function<...> has a fixed signature
  • bind expressions do not have a fixed signature. The whole purpose of bind is to change the signature. This includes e.g.

    • adding state to fill in for formal parameters dropped from the signature or
    • adding parameters, to be ignoring by not binding them to the target callable
    • changing the argument/return type by using implicit conversions
    • even changing the order in which parameters are bound to the target callable, while the signature could technically be unchanged.

So while you cannot assign different func<...> types to eachother, you can always bind the one signature to the other.

Here's a more complete demonstration that shows the limits of what you can do with function and bind, and why (how it behaves): Live On Coliru:

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <cassert>

int foo0() { return 0; }
int foo1(int) { return 1; }
int foo2(int,int) { return 2; }
int foo3(int,int,int) { return 3; }

int main()
{
boost::function<int()> func0;
boost::function<int(int)> func1;
boost::function<int(int,int)> func2;
boost::function<int(int,int,int)> func3;

// "straight" assignment ok:
// -------------------------
func0 = foo0; assert (0 == func0());
func1 = foo1; assert (1 == func1(-1));
func2 = foo2; assert (2 == func2(-1,-1));
func3 = foo3; assert (3 == func3(-1,-1,-1));

// "mixed" assignment not ok:
// --------------------------
// func0 = foo1; // compile error
// func3 = foo2; // compile error
// func1 = func2; // compile error, just the same
// func2 = func1; // compile error, just the same

// SOLUTION: you can always rebind:
// --------------------------------
func0 = boost::bind(foo3, 1, 2, 3); assert (func0() == 3);
func3 = boost::bind(foo1, _3); assert (func3(-1,-1,-1) == 1);
func3 = boost::bind(foo2, _3, _2); assert (func3(-1,-1,-1) == 2);
// same arity, reversed arguments:
func3 = boost::bind(foo3, _3, _2, _1); assert (func3(-1,-1,-1) == 3);

// can't bind more than number of formal parameters in signature:
// --------------------------------------------------------------
// func3 = boost::bind(foo1, _4); // in fact, the bind is fine, but assigning to `func3` fails
}

All asserts pass. You can try what the compiler says when you uncomment the lines that don't compile.

Cheers



Related Topics



Leave a reply



Submit