广义捕获

Version >= C++ 14

Lambdas 可以捕获表达式,而不仅仅是变量。这允许 lambdas 存储仅移动类型:

auto p = std::make_unique<T>(...);

auto lamb = [p = std::move(p)]() //Overrides capture-by-value of `p`.
{
  p->SomeFunc();
};

这将外部 p 变量移动到 lambda 捕获变量,也称为 plamb 现在拥有 make_unique 分配的内存。因为闭包包含一个不可复制的类型,这意味着 lamb 本身是不可复制的。但它可以移动:

auto lamb_copy = lamb; //Illegal
auto lamb_move = std::move(lamb); //legal.

现在 lamb_move 拥有记忆。

请注意,std::function<> 要求存储的值是可复制的。你可以编写自己的仅移动要求 std::function ,或者你可以将 lambda 填充到 shared_ptr 包装器中:

auto shared_lambda = [](auto&& f){
  return [spf = std::make_shared<std::decay_t<decltype(f)>>(decltype(f)(f))]
  (auto&&...args)->decltype(auto) {
    return (*spf)(decltype(args)(args)...);
  };
};
auto lamb_shared = shared_lambda(std::move(lamb_move));

获取我们的仅移动 lambda 并将其状态填充到共享指针然后返回可以复制的 lambda,然后存储在 std::function 或类似的中。

广义捕获使用 auto 类型推导变量的类型。默认情况下,它会将这些捕获声明为值,但它们也可以是引用:

int a = 0;

auto lamb = [&v = a](int add) //Note that `a` and `v` have different names
{
  v += add; //Modifies `a`
};

lamb(20); //`a` becomes 20.

Generalize 捕获根本不需要捕获外部变量。它可以捕获任意表达式:

auto lamb = [p = std::make_unique<T>(...)]()
{
    p->SomeFunc();
}

这对于为 lambda 提供它们可以容纳和可能修改的任意值非常有用,而无需在 lambda 外部声明它们。当然,只有在 lambda 完成其工作后你不打算访问这些变量时,这才有用。