std::move_only_function 是 C++23 引入的仅支持移动语义的函数包装器,用于封装 unique_ptr、mutex 等不可拷贝的可调用对象,满足 MoveConstructible/MoveAssignable 要求,不支持拷贝和 target 相关反射接口。

std::move_only_function 是 C++23 引入的新特性,用来替代传统 std::function 中“仅支持可复制”这一限制,专为**只可移动(move-only)的可调用对象**设计。它不强制要求底层可调用对象支持拷贝,因此能包装 lambda 捕获了 unique_ptr、fstream、mutex 或其他不可拷贝资源的闭包,也能包装 std::unique_ptr<:any_callable> 等 move-only 类型。
为什么需要 move_only_function?
std::function 要求其模板参数 F 必须满足 CopyConstructible。这意味着:如果你写了一个捕获了 std::unique_ptr 的 lambda,它本身不可拷贝,就无法存入 std::function —— 编译直接失败。
而 std::move_only_function 只要求 MoveConstructible 和 MoveAssignable,彻底解除了拷贝约束,让 move-only 逻辑可以自然封装和传递。
基本用法与声明方式
它的模板形参和调用签名声明方式与 std::function 高度一致:
立即学习“C++免费学习笔记(深入)”;
- 声明格式:
std::move_only_function,例如std::move_only_function - 可由任何满足调用签名且可移动的可调用对象构造:lambda(含 move-only 捕获)、函数指针、move-only functor、std::unique_ptr
等 - 不提供
.target()、.target_type()等反射接口(因 move-only 存储通常需类型擦除 + 动态分配,元信息难保全)
典型使用场景示例
以下代码展示如何包装一个带 unique_ptr 捕获的 lambda:
auto make_move_only_task() {
auto ptr = std::make_unique(42);
// 此 lambda 不可拷贝(unique_ptr 不可拷贝)
return std::move_only_function{[ptr = std::move(ptr)]() mutable {
return *ptr;
}};
}
int main() {
auto f = make_move_only_task(); // OK: 移动构造
// auto f2 = f; // ❌ 编译错误:不可拷贝
auto f3 = std::move(f); // ✅ 合法:可移动
std::cout << f3() << "\n"; // 输出 42
}
再比如包装一个临时的 std::unique_ptr<:function>> 或自定义 move-only 函数对象,也都适用。
注意事项与限制
- 不能隐式转换为函数指针(即使目标是普通函数),因为 move-only 语义与函数指针的无状态本质冲突
- 空状态检查仍用
if (f),但调用前务必判空(和 std::function 一致) - 性能上:内部通常依赖堆分配(类似 std::function),但实现可优化(如 small-buffer 优化对 move-only 类型更友好)
- 不兼容旧标准:C++20 及更早无此类型;需编译器支持(GCC 13+、Clang 16+、MSVC 19.35+)并启用
-std=c++23
它不是 std::function 的“升级版”,而是互补角色:需要拷贝时用 std::function,只需移动时用 move_only_function —— 更精准表达意图,也更安全。











