You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将捕获不可拷贝对象的Lambda移动到std::function中?

问题原因

std::function<void()>的构造要求传入的可调用对象必须支持拷贝构造——它的内部类型擦除机制依赖拷贝语义管理存储的函数对象。你的Lambda捕获了不可拷贝的test_t对象,导致Lambda本身也成为不可拷贝类型,因此无法构造std::function。

解决方案

针对C++20环境,有两种可行的解决方式:

方式1:使用std::move_only_function(推荐)

C++20新增了std::move_only_function,这是专门为仅移动可调用对象设计的函数包装器,完全适配你的场景。修改代码如下:

#include <functional>

class test_t {
public:
    test_t() = default;
    ~test_t() = default;

    test_t(const test_t&) = delete;
    auto operator=(const test_t&) = delete;

    test_t(test_t&& other) noexcept = default;
    auto operator=(test_t&& other) noexcept -> test_t & = default;
};

// 将参数替换为仅移动的函数包装器
auto func_a(std::move_only_function<void()> f) {
}

int main() {
    test_t a;
    auto f = [b = std::move(a)]() mutable {};
    func_a(std::move(f)); // 编译通过
}

方式2:用智能指针间接持有test_t

如果编译器对std::move_only_function支持不全,可以通过std::shared_ptr包裹test_t,让Lambda的捕获变为可拷贝类型(因为std::shared_ptr支持拷贝),从而兼容std::function:

#include <functional>
#include <memory>

class test_t {
public:
    test_t() = default;
    ~test_t() = default;

    test_t(const test_t&) = delete;
    auto operator=(const test_t&) = delete;

    test_t(test_t&& other) noexcept = default;
    auto operator=(test_t&& other) noexcept -> test_t & = default;
};

auto func_a(std::function<void()> f) {
}

int main() {
    auto a_ptr = std::make_shared<test_t>();
    auto f = [a_ptr]() mutable {}; // Lambda现在可拷贝
    func_a(f); // 直接传递即可
}

额外选项:升级到C++23

C++23对std::function进行了扩展,允许构造仅移动的可调用对象。如果能升级编译标准,无需修改func_a的参数类型,直接使用std::move(f)传入原代码即可正常编译。

内容的提问来源于stack exchange,提问作者microlife

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 02:58:22