I am learning asio programming of c++ Boost library. And I have encountered many examples that use the function bind() which has function pointer as argument.
I have not been able to understand the use of bind() function. And that's why I have difficulty in understanding programs using asio of boost library.
I am not seeking for any code here. I just want to know the use of bind() function or any of its equivalent function.
Thanks in advance.
From cppreference
The function template bind generates a forwarding call wrapper for f.
Calling this wrapper is equivalent to invoking f with some of its
arguments bound to args.
Check the example below demonstrating bind
#include <iostream>
#include <functional>
using namespace std;
int my_f(int a, int b)
{
return 2 * a + b;
}
int main()
{
using namespace std::placeholders; // for _1, _2, _3...
// Invert the order of arguments
auto my_f_inv = bind(my_f, _2, _1); // 2 args b and a
// Fix first argument as 10
auto my_f_1_10 = bind(my_f, 10, _1); // 1 arg b
// Fix second argument as 10
auto my_f_2_10 = bind(my_f, _1, 10); // 1 arg a
// Fix both arguments as 10
auto my_f_both_10 = bind(my_f, 10, 10); // no args
cout << my_f(5, 15) << endl; // expect 25
cout << my_f_inv(5, 15) << endl; // expect 35
cout << my_f_1_10(5) << endl; // expect 25
cout << my_f_2_10(5) << endl; // expect 20
cout << my_f_both_10() << endl; // expect 30
return 0;
}
You can use bind to manipulate an existing function's argument order or fix some arguments. This can be particularly helpful in stl container and algorithms where you can pass an existing library function whose signature matches with your requirement.
For example if you want to transform all your doubles in your container to power 2, you can simply do something like:
std::transform(begin(dbl_vec),
end(dbl_vec),
begin(dbl_vec),
std::bind(std::pow, _1, 2));
Live example here
The tasks that you post to a boost::asio
service have to be invokable with zero arguments so that the service can store them and invoke them once it has the spare resources (i.e. idle threads). Say you want it to call the function void purr(int kitty)
, in order to give this to the service in a format it can work with you need to bind the kitty
argument to the purr
function. This will give you an object which is invokable with ()
no arguments that you can provide to the service.
Of course with C++11 and lambda functions the best way to do this now is to do io_service.post([&](){ purr(3); });
and avoid using bind
altogether.
It allows you to associate (or "bind") your own data with a function that you want a library to call, without the library needing to know anything about your data.
Since you're looking at Boost.Asio, have a look at their tutorial for binding arguments to a handler. They have a function that they want to use as a handler, which needs pointers to their own data, the timer itself and a counter:
void print(const boost::system::error_code& /*e*/,
boost::asio::deadline_timer* t, int* count)
{
// ...
}
The timer's async_wait
function causes a user-provided function to be called when the timer expires; but only provides the first of these arguments. The handler is of the form
void handler(
const boost::system::error_code& error // Result of operation.
);
So we can use bind
to transform our function (wanting three arguments) into one that only wants one argument, by specifying values to be passed as the other two:
t.async_wait(boost::bind(print,
boost::asio::placeholders::error, &t, &count));
The result of bind
is a function object (that is, an object of a class type that overloads the function-call operator, operator()
), which in this case takes a single argument. The placeholders::error
argument says that the first argument is still an argument of the new function type; the other two arguments are given the values of &t
and &count
when the new function is called. So if we were to call this ourselves:
auto f = boost::bind(print, boost::asio::placeholders::error, &t, &count)
f(some_error);
this would have the same effect as calling the original function with those arguments:
print(some_error, &t, &count);
Now, when the timer expires, our function is called, with arguments that we provided, without the Asio library needing to know anything about them.