编译器告诉我我正在尝试访问已删除的函数(即lambda表达式的复制构造函数)。但我不知道在哪里。
std::vector<std::function<void()>> tasks;
std::packaged_task<int()> task{ [] { return 1; } };
tasks.emplace_back(
[ t = std::move(task) ] () mutable { t(); });
(我试图找出他们在https://www.slideshare.net/GlobalLogicUkraine/c11-multithreading-futures中使用shared_ptr<task>
的原因。)
在Gcc和MSVC上我得到同样的错误 - 我担心我做错了什么......
error: use of deleted function
'main()::<lambda()>::<lambda>(const main()::<lambda()>&)'
为什么我不能将此std::function
置于向量上?
答案 0 :(得分:4)
来自cppreference:
F必须符合Callable和CopyConstructible
的要求
其中F
是用于构造std::function
的函数类型。但是,std::packaged_task
是not copy constructible。因此,在捕获列表中,t
不是可复制构造的,并且是lambda的非静态成员,使得lambda的隐式复制构造函数被删除。
答案 1 :(得分:2)
简短回答:Lambdas和std::packaged_task
不是std::function
。
答案很长,您无法将std::packaged_task
移到std::function
以下是我提供的解决方案:
std::vector<std::packaged_task<int()>> tasks;
std::packaged_task<int()> task{ [] () mutable { return 1; } };
tasks.emplace_back( std::move(task) );
如果你真的需要一个std :: function,而不仅仅是任何可调用的,你必须将lambda绑定到std::function
答案 2 :(得分:0)
std::function
的构造函数要求传递的函数对象为CopyConstructible
,但std::packaged_task<F>
不是(对于任何F
)。 std::function
执行 type erasure ,其中动态类型在静态类型中不可见。考虑例如:
int invoke(std::function<int()> f) { return f(); }
int main()
{
std::packaged_task<int()> p{/*etc*/};
auto l = [] { return 5; };
std::function<int()> f( /* either p or l */ );
std::cout << invoke(f) << '\n';
}
对invoke
的调用需要复制f
(按值传递)。但是,f
如果是l
,则可以复制,但如果是p
,则不可复制,这与{{1}的静态类型无关}}。这个问题基本上有三种方法:
f
。std::function
,但如果包含的类型不可复制,则抛出运行时错误。std::function
,并要求您放入其中的任何函数对象都可以复制。方法#1对如何存储,传递和共享函数有非常严格的限制,并且基本上禁止使用不可复制的函数对象的常见用例。
方法#2是有问题的,因为用户需要接受教育,在某些情况下复制std::function
可能会失败并在编写代码时使用尽职调查。此外,如果设计需要共享功能,则可能需要将其包装在std::function
中。如果他们需要被复制并且可能是有状态的,那就更糟了。
无论你如何看待方法#3,它都是标准化的方法。但鉴于上述问题,也很容易捍卫。
事实上,我编写了一个std::shared_ptr
类模板,它使用方法#1进行当前项目,因为对我们来说,存储不可复制的异步任务对象的用例很常见,并且复制或者分享这样的任务是没有必要的。