如何将std::function作为参数传递给赋值运算符?VS2022编译问题
解决Visual Studio 2022中std::function与赋值初始化的编译错误
你的代码里,CFinallyCallFunction fn1([] {});可以编译通过,但CFinallyCallFunction fn2 = [] {};报以下错误:
错误 C2440 “初始化”: 无法从“Test::<lambda_2>”转换为“CFinallyCallFunction”
问题原因
这是C++初始化规则限制导致的:
- 直接初始化(括号形式)时,编译器会将lambda隐式转换为构造函数的参数类型
std::function<void(void)>,这是一次合法的用户定义转换,因此能成功调用构造函数。 - 拷贝初始化(等号形式)时,要求表达式到目标类型的隐式转换序列最多包含一次用户定义转换。而这里需要先把lambda转成
std::function(第一次用户定义转换),再把std::function转成CFinallyCallFunction(第二次用户定义转换),违反了规则,因此编译失败。
解决方案
方案1:添加模板构造函数(推荐)
给类添加一个模板构造函数,直接接受任意可调用对象,跳过中间的std::function转换,两种初始化方式都能适配:
class CFinallyCallFunction { public: // 保留原有的std::function构造函数 CFinallyCallFunction(const std::function<void(void)>& finallyFn) : m_finallyFn(finallyFn) {} // 添加模板构造函数,直接接收可调用对象 template<typename Callable> CFinallyCallFunction(Callable&& finallyFn) : m_finallyFn(std::forward<Callable>(finallyFn)) {} ~CFinallyCallFunction() { if (m_finallyFn != nullptr) m_finallyFn(); } // 可选:给赋值运算符也添加模板版本,支持直接赋值lambda void operator=(const std::function<void(void)>& finallyFn) { m_finallyFn = finallyFn; } template<typename Callable> void operator=(Callable&& finallyFn) { m_finallyFn = std::forward<Callable>(finallyFn); } protected: std::function<void(void)> m_finallyFn; };
方案2:显式转换lambda为std::function
如果不想修改类定义,可以手动将lambda转换成std::function,让拷贝初始化仅需一次转换:
void Test() { CFinallyCallFunction fn2 = static_cast<std::function<void()>>([] {}); // 编译通过 }
内容的提问来源于stack exchange,提问作者Matthew Dodd
相关产品推荐
相关产品推荐

