Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I move an element into vector of non-copyables?

The compiler tells me I'm trying to access a deleted function (i.e. the copy constructor of a lambda expression). But I don't see where.

std::vector<std::function<void()>> tasks;
std::packaged_task<int()> task{ [] { return 1; } };
tasks.emplace_back(
    [ t = std::move(task) ] () mutable { t(); });

(code is also here)

(I'm trying to find out why they use shared_ptr<task> in https://www.slideshare.net/GlobalLogicUkraine/c11-multithreading-futures).

On Gcc and MSVC I get the same error - I fear I'm doing something wrong...

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

Why can't I emplace this std::function onto the vector?

like image 994
xtofl Avatar asked Jun 06 '17 07:06

xtofl


2 Answers

From cppreference:

F must meet the requirements of Callable and CopyConstructible

Where F is the function type used to construct the std::function. However, std::packaged_task is not copy constructible. Thus in the capture list, t is not copy constructible, and is a non-static member of the lambda, making the implicit copy constructor for the lambda deleted.

like image 121
Weak to Enuma Elish Avatar answered Oct 31 '22 08:10

Weak to Enuma Elish


Short answer: Lambdas and std::packaged_task are not std::functions.

Long answer, you cannot move a std::packaged_task into a std::function

Here's what I'm offering as a solution:

std::vector<std::packaged_task<int()>> tasks;
std::packaged_task<int()> task{ [] () mutable { return 1; } };
tasks.emplace_back( std::move(task) );

If you actually need a std::function, and not just any callable, you'll have to bind a lambda into a std::function

like image 37
David LUC Avatar answered Oct 31 '22 08:10

David LUC