What is the right way to pass an object created by std::bind to a function?

778 views Asked by At

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

compiler error

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?

4

There are 4 answers

3
NutCracker On

It should be:

void worker(std::function<void(int)> const& callback) {
    callback(111);
}

because then implicit conversion from foo to temporary std::function object can be made.

0
NathanOliver On

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); };
5
Remy Lebeau On

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.

0
Chris Dodd On

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);
}