Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

This answer explains how to move-capture a variable within a lambda in C++14.

But once you've move-captured an un-copyable object (such as a std::unique_ptr) within a lambda, you cannot copy the lambda itself.

This would be fine if you could move the lambda, but I get a compile error when trying to do so:

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(); } 

This produces the following error with g++ (I've attempted to copy only the relevant line):

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

...implying, I think, that my attempt to move the lambda has failed.

clang++ gives a similar error.

I tried explicitly moveing the lambda (even though it's a temporary value), but that did not help.

EDIT: The answers below adequately address the compile errors produced by the above code. For an alternate approach, simply release the unique pointer's target value into a std::shared_ptr, which can be copied. (I'm not writing this as an answer, because that would assume that this is an XY problem, but the underlying reason why unique_ptr can't be used in a lambda that gets converted to a std::function is important to understand.)

EDIT 2: Hilariously enough, I just realized auto_ptr would actually do the right thing here (!), as far as I can tell. It acts essentially like unique_ptr, but allows copy-construction in place of move-construction.

like image 813
Kyle Strand Avatar asked Sep 09 '15 18:09

Kyle Strand


People also ask

How are lambdas stored?

The Lambda service stores your function code in an internal S3 bucket that's private to your account. Each AWS account is allocated 75 GB of storage in each Region. Code storage includes the total storage used by both Lambda functions and layers.

What is auto lambda expression?

Immediately invoked lambda expression is a lambda expression which is immediately invoked as soon as it is defined. For example, #include<iostream> using namespace std; int main(){ int num1 = 1; int num2 = 2; // invoked as soon as it is defined auto sum = [] (int a, int b) { return a + b; } (num1, num2);

Are lambdas copyable?

Copying a lambda will copy its state.

What does it mean to lambda capture this?

The lambda is capturing an outside variable. A lambda is a syntax for creating a class. Capturing a variable means that variable is passed to the constructor for that class. A lambda can specify whether it's passed by reference or by value.


1 Answers

You can move the lambda, that's fine. That's not what your problem is though, you're trying to instantiate a std::function with a noncopyable lambda. And the:

template< class F >  function( F f ); 

constructor of function does:

5) Initializes the target with a copy of f.

This is because std::function:

satisfies the requirements of CopyConstructible and CopyAssignable.

Since function has to be copyable, everything you put into it must also be copyable. And a move-only lambda does not meet that requirement.

like image 199
Barry Avatar answered Sep 25 '22 06:09

Barry