为什么这个代码片段有效? 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 中。