为何Boost.Signals2可接受operator()返回lambda的QtInjector类实例作为槽?
核心原因
Boost.Signals2 对槽的要求远宽松于 Qt 内置的信号槽机制,它不需要槽函数有任何特殊的元对象声明,只要是符合**可调用(Callable)**概念的对象都可以作为槽绑定到信号上。
你自定义的 QtInjector 类实现了模板化的 operator() 运算符,属于标准的可调用对象,自然可以被 Boost.Signals2 正常识别。
细节说明
- 可调用对象的适配逻辑
Boost.Signals2 内部通过类型萃取技术校验传入的槽是否可以匹配信号的参数列表:只要你的类实现的operator()可以接收信号发出的所有参数、返回值符合信号要求(你这里是 void 返回),库内部的槽包装逻辑就可以正常调用它,不需要额外的适配代码。 - 你贴出的代码存在笔误
你当前贴的QtInjector::operator()多嵌套了一层无意义的 lambda:调用operator()时只会返回一个新的可调用对象,不会实际执行QMetaObject::invokeMethod投递任务。如果实测效果和injectToQt完全一致,说明你实际运行的代码里没有这层多余的 lambda,operator()内部直接执行了投递逻辑。
修正后的标准实现应该是:template<class TObj, class TFunc> class QtInjector { public: QtInjector(TObj obj, TFunc fn) : obj(obj), fn(std::move(fn)) {} template<class ... TParams> void operator()(TParams&& ... params) const { QMetaObject::invokeMethod(obj, [fn = this->fn, params = std::make_tuple(std::forward<TParams>(params)...)](){ std::apply(fn, params); }, Qt::QueuedConnection); } private: TFunc fn; TObj obj; }; - 使用注意事项
你当前的实现依赖 Qt 5.10 及以上版本提供的invokeMethod直接支持 lambda 重载,低版本 Qt 需要额外传入一个继承QObject的上下文对象才能正常工作。另外值捕获参数对于大尺寸参数会产生额外拷贝,你可以通过完美转发+移动捕获的方式优化性能。
内容的提问来源于stack exchange,提问作者Gustavo
相关产品推荐
相关产品推荐

