应改用 std::move_only_function——因其仅要求 MoveConstructible,可容纳捕获 unique_ptr 等 non-copyable 类型的 lambda,而 std::function 强制 CopyConstructible 导致编译失败。

遇到 error: use of deleted function 'X::X(const X&)' 就该换 std::move_only_function——这不是写法问题,是语义冲突:你试图塞进 std::function 的 lambda 捕获了 std::unique_ptr、std::mutex 或其他 non-copyable 类型,它天然不满足 CopyConstructible,而 std::function 强制要求这个约束。
为什么 std::function 编译失败,而 std::move_only_function 可以
std::function 在构造时就做拷贝可行性检查;一旦目标类型删了拷贝构造(比如捕获 std::unique_ptr 的 lambda),编译器立刻报错。这不是你漏写了 mutable 或参数错了,是类型系统在说“这事根本不能做”。std::move_only_function 绕过拷贝检查,只依赖 MoveConstructible,且底层不预留虚函数表项、不存引用计数字段——所以零开销,也无运行时兜底。
- 能直接接:
[ptr = std::make_unique<int>(42)]() mutable { return *ptr; }</int> - 不能直接接可拷贝 lambda:
[x = 42]() { return x; },必须显式 move 构造:std::move_only_function<int>{std::move(lambda)}</int> - 捕获引用如
[&x]本身不阻止拷贝,但 move 后原闭包失效,x成悬垂引用,运行时崩溃风险高
std::move_only_function 模板参数必须手写完整签名
它没有 make_move_only_function 辅助函数,也不支持 auto 推导。漏写任何调用限定符(noexcept、const、&、&&)都会导致类型不匹配,甚至调用时异常传播失控。
- 正确:
std::move_only_function<void noexcept></void>、std::move_only_function<int const std::string></int>、std::move_only_function<double></double> - 错误:
std::move_only_function<void></void>(缺括号和参数列表)、std::move_only_function<void></void>(漏noexcept,而被封装函数带noexcept) - 错误:
auto f = std::move_only_function{}(模板参数无法推导)、std::move_only_function f = lambda(缺少模板参数,编译失败)
往 std::vector 存或传参时必须显式 std::move
所有“转移所有权”的操作都强制显式 std::move,编译器不会隐式转换,也不会给你运行时兜底——漏掉就直接编译失败。
立即学习“C++免费学习笔记(深入)”;
-
std::vector<:move_only_function>> tasks;</:move_only_function>→tasks.push_back(std::move(task));,不能写tasks.push_back(task); - 函数参数建议用右值引用:
void enqueue(std::move_only_function<void> &&task)</void>,避免入口处尝试拷贝 - 类成员含
std::move_only_function时,移动赋值操作符必须手动定义为= default或逐个std::move
空值检查和调用后状态管理最容易被忽略
std::move_only_function 空初始化合法:std::move_only_function<void> f;</void>,但调用前必须用 if (f) 检查是否为空;调用后原对象进入有效但未指定状态(通常为空),再次调用未定义行为。它不支持 target() 或 target_type(),move-only 类型擦除后无法安全还原原始类型——这部分能力被主动舍弃。
最常踩的坑不是语法写错,而是把 std::move_only_function 当成“轻量版 std::function”来用:它不是替代品,是唯一能合法收下 move-only callable 的容器;它不兜底、不推导、不还原、不隐式移动——每一步都得你亲手确认。


















