通过lambda向std::thread转发函数出现function类型错误如何解决?
报错根本原因
- 模板推导规则触发隐式类型问题:传入左值函数
f时,万能引用Function&&会将Function推导为函数左值引用类型int (&)(int)。 - lambda按值捕获的类型限制:按值捕获类型为函数引用的
function变量时,闭包类会生成一个和引用目标同类型的成员,也就是int(int)函数类型,C++标准不允许类的非静态成员为函数类型,直接触发类型非法错误。
修复方案
只需要修改lambda的捕获逻辑,将函数引用退化为函数指针即可,有两种常用修改方式:
- 用完美转发初始化捕获,自动完成类型退化:
// 把原来的捕获行[function, ...]改成下面的写法 auto lambda = [function = std::forward<Function>(function), promise = std::move(outer_promise)](Args&&... args) mutable {
- 显式指定类型退化:
#include <utility> // 要用到std::decay_t auto lambda = [function = static_cast<std::decay_t<Function>>(function), promise = std::move(outer_promise)](Args&&... args) mutable {
额外优化建议
泛型代码中建议用std::invoke调用可调用对象,同时对参数做完美转发,兼容性更强:
// 把promise.set_value(function(args...))改成 promise.set_value(std::invoke(std::forward<Function>(function), std::forward<Args>(args)...));
修正后完整可运行代码
#include <future> #include <iostream> #include <thread> #include <chrono> #include <ctime> #include <type_traits> #include <utility> int f(int x) { auto start = std::chrono::system_clock::now(); std::time_t start_time = std::chrono::system_clock::to_time_t(start); std::cout << "returning " << x << " at " << std::ctime(&start_time) << std::endl; return x; } template<typename Function, typename... Args> auto async(Function&& function, Args&&... args) { using ReturnType = typename std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...>; std::promise<ReturnType> outer_promise; auto future = outer_promise.get_future(); auto lambda = [function = std::forward<Function>(function), promise = std::move(outer_promise)] (Args&&... args) mutable { try { promise.set_value(std::invoke(function, std::forward<Args>(args)...)); } catch (...) { promise.set_exception(std::current_exception()); } }; std::thread t0(std::move(lambda), std::forward<Args>(args)...); t0.detach(); return future; } int main() { auto result1 = async(f, 1); auto result2 = async(f, 2); // 等待异步任务完成,避免主线程提前退出 result1.wait(); result2.wait(); return 0; }
内容的提问来源于stack exchange,提问作者Jamie C.
相关产品推荐
相关产品推荐

