Let's assume I want to pass a function object created by std::bind
by reference to a funktion:
void myCallback(int i, int j)
{
std::cout << "toCall , i=" << i << " j=" << j;
}
void worker(std::function<void(int)> & callback)
{
callback(111);
}
int main(int argc, char** argv)
{
auto foo = std::bind(myCallback, std::placeholders::_1, 222);
worker(foo);
}
This does not compile
Severity Code Description Project File Line Suppression State Error C2664 'void worker(std::function &)': cannot convert argument 1 from 'std::_Binder &,int>' to 'std::function &' asn1test_1 D:.....\asn1test_1.....cpp 302
However, passing by value works:
void worker(std::function<void(int)> callback)
{
callback(111);
}
When I avoid "auto
" and use instead
std::function<void(int)> foo = std::bind(myCallback, std::placeholders::_1, 222);
it works both with passing by reference or by value.
Q1: Why this behavior?
Q2: What would be the "right" way or datatype to pass an object created by std::bind
to a function?
std::bind is a Standard Function Objects that acts as a Functional Adaptor i.e. it takes a function as input and returns a new function Object as an output with with one or more of the arguments of passed function bound or rearranged.
std::bind allows you to create a std::function object that acts as a wrapper for the target function (or Callable object). std::bind also allows you to keep specific arguments at fixed values while leaving other arguments variable.
boost::bind is a generalization of the standard functions std::bind1st and std::bind2nd. It supports arbitrary function objects, functions, function pointers, and member function pointers, and is able to bind any argument to a specific value or route input arguments into arbitrary positions.
std::bind
does not return a std::function
, at least, it is not required to do so. When you do
auto foo = std::bind(myCallback, std::placeholders::_1, 222);
worker(foo);
foo
is not a std::function
and worker
needs a non-const reference to a std::function
, so the compiler errors out. If you switch worker
to being
void worker(const std::function<void(int)> & callback)
then you'll have a const reference and that can be bound to the temporary object that the conversion of foo
to a std::function
would produce.
I'd also like to point out that since we have lambdas, especially generic ones, std::bind
really isn't needed. Keeping the change to worker, you could instead make foo
auto foo = [](auto var){ return myCallback(var, 222); };
std::bind()
does not return a std::function
, but an implementation-defined type that is convertible to a std::function
.
When worker()
takes its callback
parameter as a non-const reference, that prevents the compiler from performing any implicit conversions, as a non-const reference cannot be bound to a temporary object. The reference will require an actual std::function
object to have been created explicitly beforehand, eg:
std::function<void(int)> foo = std::bind(myCallback, std::placeholders::_1, 222);
worker(foo);
Changing worker()
to take its callback
parameter by value, or by const reference, allows the compiler to perform an implicit conversion for you, so you can pass the result of std::bind()
as-is and the compiler will create a temp std::function
for you.
If you want to avoid the overhead of converting to a std::function, you could use a template:
template<class CB> void worker(CB callback) {
callback(111);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With