如何解决捕获std::unique_ptr的Lambda无法移动到std::function的问题?
问题原因
std::function的底层实现要求它存储的可调用对象必须是可拷贝构造的。你的lambda因为捕获了std::unique_ptr(本身是不可拷贝的移动-only类型),导致整个lambda也变成了不可拷贝类型,所以直接赋值给std::function会触发target must be copy-constructible错误。
解决方案
方案1:C++23直接用std::move_only_function
C++23新增了std::move_only_function,专门用来存储不可拷贝的可调用对象,完美适配你的场景:
#include <functional> #include <memory> auto my_ptr = std::make_unique<int>(3); auto my_lambda = [my_ptr = std::move(my_ptr)]() mutable { // 这里写你的逻辑 }; std::move_only_function<void()> func = std::move(my_lambda); // 结构体中可以直接声明 struct MyStruct { std::move_only_function<void()> func; };
方案2:兼容C++11/14/17的包装类
如果你的项目还不能用C++23,可以自己写一个轻量的包装类,把不可拷贝的lambda用std::unique_ptr持有,再适配成std::function接受的可调用类型:
#include <functional> #include <memory> #include <type_traits> // 包装不可拷贝的可调用对象 struct MoveOnlyWrapper { // 用unique_ptr存储对象,自定义删除器 std::unique_ptr<void, void(*)(void*)> storage; // 重载调用运算符 void operator()() const { using Callable = void(*)(); (*reinterpret_cast<Callable>(storage.get()))(); } // 模板构造函数,接受任意移动-only的可调用对象 template<typename F> MoveOnlyWrapper(F&& f) : storage( new std::decay_t<F>(std::forward<F>(f)), [](void* ptr) { delete static_cast<std::decay_t<F>*>(ptr); } ) {} }; // 使用示例 auto my_ptr = std::make_unique<int>(3); auto my_lambda = [my_ptr = std::move(my_ptr)]() mutable { // 这里写你的逻辑 }; std::function<void()> func = MoveOnlyWrapper(std::move(my_lambda)); // 结构体中声明 struct MyStruct { std::function<void()> func; };
这个包装类的核心是把lambda的实例放到堆上,用unique_ptr管理,然后通过类型擦除让std::function能识别它的调用接口。
内容的提问来源于stack exchange,提问作者UdiM
相关产品推荐
相关产品推荐

