移动 lambda:一旦您捕获了仅移动类型,如何使用 lambda?



这个答案解释了如何在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的尝试失败了。

CCD_ 3给出了类似的错误。

我尝试过显式地对lambda进行move处理(尽管它是一个临时值(,但没有帮助。

编辑:下面的答案充分解决了由上述代码产生的编译错误。对于另一种方法,只需将唯一指针的目标值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( 使用f副本初始化目标。

这是因为std::function:

满足CopyConstructable和CopyAssignable的要求。

由于function必须是可复制的,所以您放入其中的所有内容也必须是可拷贝的。只移动lambda不满足这个要求。

std::function不是lambda!它是一个包装器,可以由任何类型的可调用函数(包括lambda(构造。std::function要求可调用的是可复制构造的,这就是您的示例失败的原因。

只能移动的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));
}

实时演示

最新更新