移动 lambda:一旦你移动捕获了一个只能移动的类型,如何使用 lambda?

Moving a lambda: once you've move-captured a move-only type, how can the lambda be used?

This answer 解释了如何在 C++14 中的 lambda 中移动捕获变量。

但是一旦您在 lambda 中移动捕获了一个不可复制的对象(例如 std::unique_ptr),您将无法复制 lambda 本身。

如果您可以移动 lambda 就好了,但是我在尝试这样做时遇到编译错误:

using namespace std;

class HasCallback
{
  public:
    void setCallback(std::function<void(void)>&& f)
    {
      callback = move(f);
    }

    std::function<void(void)> callback;
};

int main()
{
  auto uniq = make_unique<std::string>("Blah blah blah");
  HasCallback hc;
  hc.setCallback(
      [uniq = move(uniq)](void)
      {
        std::cout << *uniq << std::endl;
      });

  hc.callback();
}

g++ 会产生以下错误(我试图只复制相关行):

error: use of deleted function ‘main()::<lambda()>::<lambda>(const main()::<lambda()>&’

...暗示,我认为,我尝试移动 lambda 失败了。

clang++ 给出了类似的错误。

我明确地尝试 moveing lambda(即使它是一个临时值),但这没有帮助。

编辑: 下面的答案充分解决了上述代码产生的编译错误。对于替代方法,只需 release 唯一指针的目标值到 std::shared_ptr 中, 可以 复制。 (我不是把它写成一个答案,因为那会假设这是一个 XY 问题,但是 unique_ptr 不能在转换为 std::function 的 lambda 中使用的根本原因理解很重要。)

编辑 2: 够搞笑的,我刚刚意识到 auto_ptr 实际上会在这里做正确的事(!),据我所知。它的行为本质上类似于 unique_ptr,但允许复制构造代替移动构造。

您可以移动 lambda,没关系。不过,这不是您的问题所在,您正在尝试使用不可复制的 lambda 实例化 std::function。还有:

template< class F > 
function( F f );

function 的构造函数:

5) Initializes the target with a copy of f.

这是因为std::function:

satisfies the requirements of CopyConstructible and CopyAssignable.

由于function必须是可复制的,所以你放入其中的所有内容也必须是可复制的。而仅移动的 lambda 不满足该要求。

std::function 不是 lambda!它是一个包装器,可以从任何类型的可调用对象构造,包括 lambda。 std::function 要求 callable be copy-constructible,这就是您的示例失败的原因。

只能移动的 lambda 可以再次移动,如下所示。

template<typename F>
void call(F&& f)
{
    auto f1 = std::forward<F>(f);  // construct a local copy
    f1();
}

int main()
{
  auto uniq = make_unique<std::string>("Blah blah blah");
  auto lambda = [uniq = move(uniq)]() {
        std::cout << *uniq << std::endl;
      };
//  call(lambda);   // doesn't compile because the lambda cannot be copied
  call(std::move(lambda));
}

Live demo