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

时间:2015-09-09 18:17:30

标签: c++ lambda move c++14

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++给出了类似的错误。

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

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

编辑2:非常滑稽,我只是意识到unique_ptr实际上会在这里做正确的事(!),据我所知。它的行为基本上类似于angular.module("myApp") .factory("utentiService", function($http) { return { getData: function () { return $http.get("backListaUtenti.php").then(function (response) { return response.data; }); } }; }); angular.module("myApp") .controller("utenteCtrl", function($scope, $routeParams, utentiService, filterFilter) { var userId = $routeParams.userId; utentiService.getData().then(function(data) { $scope.utente = filterFilter(data, { id: userId })[0]; }); }); angular.module("myApp") .controller("listaUtentiCtrl", function($scope, utentiService) { utentiService.getData().then(function (data) { $scope.utenti = data; }); }); ,但允许复制构造代替移动构造。

2 个答案:

答案 0 :(得分:16)

你可以移动 lambda ,没关系。这不是你的问题,你试图用不可复制的lambda实例化std::function。而且:

template< class F > 
function( F f );
<{3}}的

构造函数确实:

  

5)使用f副本初始化目标。

这是因为function

  

满足CopyConstructible和CopyAssignable的要求。

由于function必须是可复制的,因此您放入其中的所有内容也必须是可复制的。并且只有移动的lambda不符合该要求。

答案 1 :(得分:12)

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