Why does this code snippet work?
#include <functional>
#include <iostream>
#include <memory>
int main()
{
std::unique_ptr<int> ptr(new int(666));
std::bind([](std::unique_ptr<int> &ptr){std::cout << *ptr << std::endl;}, std::move(ptr))();
}
You see the parameter of the lambda should be a lvalue-reference, whereas std::bind
pass a rvalue(i.e. std::move(ptr)
) to it.
Also, why does this code snippet not compile?
std::function<void()> = std::bind([](std::unique_ptr<int> &ptr){std::cout << *ptr << std::endl;}, std::move(ptr));
Just because std::function
need copy all the objects, whereas std::move(ptr)
is not copyable?
CodePudding user response:
std::bind()
does not call the lambda, it returns a proxy that will call the lambda when the proxy is invoked later. So, just because you pass in an rvalue reference into std::bind()
does not mean the proxy will pass an rvalue reference into the lambda.
And in fact, if you think about it, the proxy can't do so anyway. It has to move your rvalue-referenced unique_ptr
object into something in the proxy to save it for later use after std::bind()
has exited. And that something is itself not an rvalue, and so that something can then be passed into the lambda by lvalue reference.
CodePudding user response:
std::bind pass a rvalue ... to it
Yes, an rvalue was passed to std::bind
. It was duly stashed away for safe-keeping, until such time that the bound callable object gets called.
At that time the saved object gets passed to the lambda by referenced.
In other words, the following is a gross simplification, this is what this particular std::bind
roughly ends up doing.
struct bound_function {
template<typename Arg> bound_function(Arg &&arg)
: saved_parameter{std::forward<Arg>(arg)
{
}
void operator()()
{
invoke_bound_function(saved_parameter);
}
private:
std::unique_ptr<int> saved_parameter;
void bound_function(std::unique_ptr<int> &ptr){std::cout << *ptr << std::endl;}
};
The act of binding a parameter to a callable object, and then invoking a callable object with a bound parameter, are two discrete, independent events. In the first one, the parameter is moved into the bound object, as an rvalue reference.
Invoking the bound function is a separate step, and the bound parameter gets passed to the bound function, by reference.