我应该如何正确地将 packaged_task 移动到 lambda?

How should I correctly move packaged_task to lambda?

我一直在尝试将 packaged_task 捕获到 lambda 中,但我失败了。
我完全理解移动语义,也阅读了一些现代文学,我想我没有错过任何东西。我还阅读了 Josuttis 的移动语义书,以及关于广义 lambda 捕获和类似案例的 ISO 主题 ISO C++ 14 Language Extensions
我有下一个代码:

#include <thread>
#include <vector>
#include <functional>
#include <queue>
#include <condition_variable>
#include <mutex>
#include <future>
#include <type_traits>
#include <iostream>

// #include's for below code and other purposes

int main() {
    auto f = []() { return 1; }; 
    std::queue<std::function<void()>> q;
    std::packaged_task<int()> pack(f);
    q.emplace([p = std::move(pack)] () mutable { p(); });

    return 0;
}

我在这里创建简单的函数队列,保存一些 'void ()' 和 packaged_task,传递 'int' return 类型的 'f'。
然后我试图将 packaged_task 移动到 lambda 中以便稍后在其他线程中使用它(我需要在其他线程中使用它,这将在稍后执行它,当 'pack' 将被销毁并且这个这就是为什么我不能把它作为参考)
似乎一切都很好,但是当我用 "g++ main.cpp -o main -std=c++14"(甚至用 c++17)编译它时,g++ 告诉我:

/usr/include/c++/9/bits/std_function.h:176:6: error: use of deleted function ‘main()::::(const main()::&)’
176 | new _Functor(*__source._M_access());
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:19:32: note: ‘main()::::(const main()::&)’ is implicitly deleted because the default definition would be ill-formed:
19 | q.emplace([p = std::move(pack)] () mutable { p(); });
| ^
main.cpp:19:32: error: use of deleted function ‘std::packaged_task<_Res(_ArgTypes ...)>::packaged_task(const std::packaged_task<_Res(_ArgTypes ...)>&) [with _Res = int; _ArgTypes = {}]’
In file included from main.cpp:8:
/usr/include/c++/9/future:1511:7: note: declared here
1511 | packaged_task(const packaged_task&) = delete;
| ^~~~~~~~~~~~~

我也可以只使用shared_ptr通过将它的副本传递给lambda来解决这个问题,但这种解决问题的方式似乎太丑陋了。 那么,为什么我在尝试移动复制构造时会出错,我该如何修复它?

你的 lambda 没问题。如果将 lambda 定义移动到它自己的行,您会发现其中没有错误。

您的问题实际上在于 std::function constructor requires its argument to be CopyConstructible,并且由于您的 lambda 包含一个只能移动的对象,因此它不是 CopyConstructible。

您可以尝试 implement something similar to std::function for move-only types,或尝试以不同的方式解决您的问题。