为什么这个代码片段有效? lambda 的参数应该是一个左值引用,而 `std::bind` 传递一个右值(即 `std::move(ptr)`)给它
Why this code snippet works? The parameter of the lambda should be a lvalue-reference, whereas `std::bind` pass a rvalue(i.e. `std::move(ptr)`) to it
为什么 this code snippet 有效?
#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))();
}
你看到 lambda 的参数应该是一个左值引用,而 std::bind
传递一个右值(即 std::move(ptr)
)给它。
还有,为什么this code snippet编译不了?
std::function<void()> = std::bind([](std::unique_ptr<int> &ptr){std::cout << *ptr << std::endl;}, std::move(ptr));
就因为std::function
需要复制所有对象,而std::move(ptr)
不可复制?
更新:
上述无法编译的代码见https://localcoder.org/how-to-capture-a-unique-ptr-into-a-lambda-expression(即见post中的'solution 3')。所以上述解决方案是完全错误的。我说得对吗?
std::bind pass a rvalue ... to it
是的,右值已传递给 std::bind
。它被适当地隐藏了 safe-keeping,直到绑定的可调用对象被调用。
那时保存的对象通过引用传递给 lambda。
换句话说,下面是一个粗略的简化,这就是这个特定的 std::bind
粗略地最终做出这样的事情:
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 invoke_bound_function(std::unique_ptr<int> &ptr){std::cout << *ptr << std::endl;}
};
将参数绑定到可调用对象,然后使用绑定参数调用可调用对象的行为是两个离散的独立事件。在第一个中,参数被移动到绑定对象中,作为右值引用。
调用绑定函数是一个单独的步骤,绑定参数通过引用传递给绑定函数。
std::bind()
不调用 lambda,它 returns 一个代理,稍后调用代理时将调用 lambda。因此,仅仅因为 you 将右值引用传递给 std::bind()
并不意味着 proxy 会将右值引用传递给 lambda。
而且其实仔细想想,proxy怎么也做不到。它必须将您的 rvalue-referenced unique_ptr
对象移动到代理中的某处,以便在 std::bind()
退出后保存它以备后用。那个东西本身不是右值,因此可以通过左值引用将某些东西传递到 lambda 中。
为什么 this code snippet 有效?
#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))();
}
你看到 lambda 的参数应该是一个左值引用,而 std::bind
传递一个右值(即 std::move(ptr)
)给它。
还有,为什么this code snippet编译不了?
std::function<void()> = std::bind([](std::unique_ptr<int> &ptr){std::cout << *ptr << std::endl;}, std::move(ptr));
就因为std::function
需要复制所有对象,而std::move(ptr)
不可复制?
更新:
上述无法编译的代码见https://localcoder.org/how-to-capture-a-unique-ptr-into-a-lambda-expression(即见post中的'solution 3')。所以上述解决方案是完全错误的。我说得对吗?
std::bind pass a rvalue ... to it
是的,右值已传递给 std::bind
。它被适当地隐藏了 safe-keeping,直到绑定的可调用对象被调用。
那时保存的对象通过引用传递给 lambda。
换句话说,下面是一个粗略的简化,这就是这个特定的 std::bind
粗略地最终做出这样的事情:
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 invoke_bound_function(std::unique_ptr<int> &ptr){std::cout << *ptr << std::endl;}
};
将参数绑定到可调用对象,然后使用绑定参数调用可调用对象的行为是两个离散的独立事件。在第一个中,参数被移动到绑定对象中,作为右值引用。
调用绑定函数是一个单独的步骤,绑定参数通过引用传递给绑定函数。
std::bind()
不调用 lambda,它 returns 一个代理,稍后调用代理时将调用 lambda。因此,仅仅因为 you 将右值引用传递给 std::bind()
并不意味着 proxy 会将右值引用传递给 lambda。
而且其实仔细想想,proxy怎么也做不到。它必须将您的 rvalue-referenced unique_ptr
对象移动到代理中的某处,以便在 std::bind()
退出后保存它以备后用。那个东西本身不是右值,因此可以通过左值引用将某些东西传递到 lambda 中。