自定义function类无法转换lambda表达式的编译问题排查
以下是导致GCC报错error: conversion from 'main()::<lambda()>' to non-scalar type 'function<void()>' requested的常见原因及修复方案:
自定义function类缺少适配可调用对象的构造函数
你的function<void()>如果没有定义能接收lambda这类可调用对象的构造函数,编译器无法完成隐式转换。比如仅定义了空构造函数,或者构造函数的参数类型不匹配。
错误示例:struct function<void()> { function() = default; // 无接收可调用对象的构造函数 void operator()() {} };修复:添加带
invocable_r约束的模板构造函数(结合类型擦除实现通用存储):#include <concepts> #include <memory> #include <utility> struct function<void()> { template<std::invocable_r<void> F> function(F&& f) : impl(std::make_unique<impl_model<std::decay_t<F>>>(std::forward<F>(f))) {} void operator()() { impl->invoke(); } private: struct impl_base { virtual void invoke() = 0; virtual ~impl_base() = default; }; template<typename F> struct impl_model : impl_base { F func; impl_model(F&& f) : func(std::forward<F>(f)) {} void invoke() override { func(); } }; std::unique_ptr<impl_base> impl; };invocable_r约束参数顺序错误std::invocable_r的模板参数顺序是返回值类型在前,可调用对象类型在后,如果顺序写反,会导致约束不满足,构造函数无法匹配lambda。
错误示例:template<typename F> requires std::invocable_r<F, void> // 参数顺序颠倒 function(F&& f) {}修复:调整为正确的参数顺序:
template<typename F> requires std::invocable_r<void, F> function(F&& f) {}未实现类型擦除导致无法存储lambda
lambda是匿名的唯一类型,如果你的function<void()>是非模板类,直接存储lambda类型会因为类型不匹配失败——每个lambda的类型都不同,无法用固定类型存储。必须通过类型擦除(如虚函数、std::function封装)来统一可调用对象的接口。
错误示例(无类型擦除):struct function<void()> { template<std::invocable_r<void> F> function(F&& f) : func(f) {} // 无法存储任意F类型的对象 void operator()() { func(); } private: // 没有通用类型能存储所有符合要求的lambda F func; };修复参考第一点中的类型擦除实现。
构造函数被标记为
explicit
如果自定义function的构造函数加了explicit关键字,隐式转换会被阻止。比如直接写function<void()> f = []{};会触发报错,因为这需要隐式构造。
修复:要么去掉explicit关键字,要么改用显式构造语法:function<void()> f{[](){}}; // 显式构造
内容的提问来源于stack exchange,提问作者glades

