为何带std::function参数构造函数的类无法隐式转换为可调用对象
自定义Event类无法隐式转换可调用对象的原因及解决办法
先看你定义的Event类代码:
class Event { private: std::function<void()> m_func; public: Event(std::function<void()> func) : m_func(func) {} };
以及测试时出错的代码:
void foo() {} int main() { Event evt = foo; // 编译错误 evt = []() {}; // 编译错误 }
问题原因
C++对隐式转换有严格限制:只允许一次用户定义的隐式转换。
你提到std::function<void()> func = []() {}能正常工作,是因为这里只发生了一次隐式转换——lambda表达式直接隐式转换成std::function<void()>类型。
但到你的Event类这里:
- 对于
Event evt = foo;:需要先把函数指针foo隐式转成std::function<void()>(第一次用户定义转换),再把这个std::function传给Event的构造函数(第二次用户定义转换),连续两次隐式转换违反了C++规则,因此编译失败。 - 对于
evt = []() {};:Event类没有自定义赋值运算符,默认赋值运算符只能接受Event类型对象。要把lambda转成Event,同样需要先转成std::function再转成Event,还是两次隐式转换,且默认赋值不支持跨类型转换,所以也报错。
解决办法
方法1:添加模板构造函数与赋值运算符
让构造函数直接接受任意可调用对象,内部构造std::function,避免多次隐式转换:
class Event { private: std::function<void()> m_func; public: template<typename Callable> Event(Callable&& func) : m_func(std::forward<Callable>(func)) {} template<typename Callable> Event& operator=(Callable&& func) { m_func = std::forward<Callable>(func); return *this; } };
这样Event evt = foo;和evt = []() {};都能正常编译运行。
方法2:显式转换可调用对象
初始化或赋值时,先把可调用对象显式转换成std::function<void()>,再传给Event:
int main() { Event evt = std::function<void()>(foo); // 正常编译 evt = std::function<void()>([]() {}); // 正常编译 }
方法3:重载接受std::function的赋值运算符
如果不想用模板,可以直接给Event添加接受std::function的赋值运算符:
class Event { private: std::function<void()> m_func; public: Event(std::function<void()> func) : m_func(func) {} Event& operator=(std::function<void()> func) { m_func = std::move(func); return *this; } };
此时evt = std::function<void()>([]() {});可以正常工作,但仍需显式转换可调用对象。
内容的提问来源于stack exchange,提问作者TwistedBlizzard
相关产品推荐
相关产品推荐

