Qt SignalWaiter类模板函数编译错误:无法匹配信号类型
问题描述
想要实现一个SignalWaiter类,用于连接各类Qt信号并等待信号触发或超时,但编写的模板函数无法识别信号类型,尝试了静态Connect模板方法和模板构造函数两种实现,均出现编译错误。
第一种实现代码
SignalWaiter.h
class SignalWaiter { private: SignalWaiter(); public: template <typename Func> static std::unique_ptr<SignalWaiter> Connect(QObject* sender, Func signal); public: bool Wait(int milliseconds = 1000); private: QTimer m_timer; QEventLoop m_loop; }; template<typename Func> inlinestd::unique_ptr<SignalWaiter> SignalWaiter::Connect(QObject* sender, Func signal) { std::unique_ptr<SignalWaiter> ptr(new SignalWaiter()); QObject::connect(sender, signal, &(ptr->m_loop), &QEventLoop::quit); QObject::connect(&(ptr->m_timer), &QTimer::timeout, &(ptr->m_loop), &QEventLoop::quit); return ptr; }
SignalWaiter.cpp
SignalWaiter::SignalWaiter() { m_timer.setSingleShot(true); } bool SignalWaiter::Wait(int milliseconds) { m_timer.start(milliseconds); m_loop.exec(); return m_timer.isActive(); }
编译错误信息
warning C4834: discarding return value of function with 'nodiscard' attribute error C2665: 'QObject::connect': none of the 4 overloads could convert all the argument types message : could be 'QMetaObject::Connection QObject::connect(const QObject *,const char *,const char *,Qt::ConnectionType) const' message : or 'QMetaObject::Connection QObject::connect(const QObject *,const QMetaMethod &,const QObject *,const QMetaMethod &,Qt::ConnectionType)' message : or 'QMetaObject::Connection QObject::connect(const QObject *,const char *,const QObject *,const char *,Qt::ConnectionType)' message : or 'QMetaObject::Connection QObject::connect<Func,void(__cdecl QEventLoop::* )(void)>(const QWebEngineView *,Func1,const QEventLoop *,Func2,Qt::ConnectionType)' with [ Func=void (__cdecl QWebEngineView::* )(bool), Func1=void (__cdecl QWebEngineView::* )(bool), Func2=void (__cdecl QEventLoop::* )(void) ] message : while trying to match the argument list '(QObject *, Func, QEventLoop *, void (__cdecl QEventLoop::* )(void))' with [ Func=void (__cdecl QWebEngineView::* )(bool) ] message : see reference to function template instantiation 'std::unique_ptr<SignalWaiter,std::default_delete<SignalWaiter>> SignalWaiter::Connect<void(__cdecl QWebEngineView::* )(bool)>(QObject *,Func)' being compiled with [ Func=void (__cdecl QWebEngineView::* )(bool) ]
第二种实现(模板构造函数)
class SignalWaiter { public: template <typename Func> SignalWaiter(QObject* sender, Func signal); public: bool Wait(int milliseconds = 1000); private: QTimer m_timer; QEventLoop m_loop; }; template<typename Func> inlinelineSignalWaiter::SignalWaiter(QObject* sender, Func signal) { m_timer.setSingleShot(true); QObject::connect(sender, signal, &m_loop, &QEventLoop::quit); QObject::connect(&m_timer, &QTimer::timeout, &m_loop, &QEventLoop::quit); } inline bool SignalWaiter::Wait(int milliseconds) { m_timer.start(milliseconds); m_loop.exec(); return m_timer.isActive(); }
错误原因分析
- 模板推导匹配失败:模板函数接收的
sender是QObject*类型,但信号是派生类(如QWebEngineView)的成员函数指针。Qt新式信号槽的connect模板要求第一个参数的类型与信号所属类兼容,当sender被向上转型为QObject*后,编译器无法正确推导connect所需的模板参数,导致无法匹配到正确的重载版本。 - 参数兼容性推导问题:信号带有参数(如
void (QWebEngineView::*)(bool)),而槽函数QEventLoop::quit无参。虽然Qt允许信号参数数量多于槽,但sender类型的不明确加剧了模板推导时的参数兼容性检查失败。 - 语法拼写错误:代码中存在
inlinestd::unique_ptr(缺少空格)、inlinelineSignalWaiter(重复inline)等语法错误,直接导致编译失败。
解决方案
核心修复:明确Sender模板参数
修改模板函数,让其接收具体的Sender类型指针而非QObject*,使编译器能正确推导connect的模板参数。
修正后的静态Connect版本
SignalWaiter.h
class SignalWaiter { private: SignalWaiter(); public: // 新增Sender模板参数,接收具体发送者类型指针 template <typename Sender, typename Func> static std::unique_ptr<SignalWaiter> Connect(Sender* sender, Func signal); public: bool Wait(int milliseconds = 1000); private: QTimer m_timer; QEventLoop m_loop; }; template<typename Sender, typename Func> inline std::unique_ptr<SignalWaiter> SignalWaiter::Connect(Sender* sender, Func signal) { std::unique_ptr<SignalWaiter> ptr(new SignalWaiter()); // sender类型与信号所属类匹配,connect可正确推导模板 QObject::connect(sender, signal, &(ptr->m_loop), &QEventLoop::quit); QObject::connect(&(ptr->m_timer), &QTimer::timeout, &(ptr->m_loop), &QEventLoop::quit); return ptr; }
SignalWaiter.cpp
#include "SignalWaiter.h" SignalWaiter::SignalWaiter() { m_timer.setSingleShot(true); } bool SignalWaiter::Wait(int milliseconds) { m_timer.start(milliseconds); m_loop.exec(); return m_timer.isActive(); }
修正后的模板构造函数版本
class SignalWaiter { public: template <typename Sender, typename Func> SignalWaiter(Sender* sender, Func signal); public: bool Wait(int milliseconds = 1000); private: QTimer m_timer; QEventLoop m_loop; }; template<typename Sender, typename Func> inline SignalWaiter::SignalWaiter(Sender* sender, Func signal) { m_timer.setSingleShot(true); QObject::connect(sender, signal, &m_loop, &QEventLoop::quit); QObject::connect(&m_timer, &QTimer::timeout, &m_loop, &QEventLoop::quit); } inline bool SignalWaiter::Wait(int milliseconds) { m_timer.start(milliseconds); m_loop.exec(); return m_timer.isActive(); }
使用示例
调用时直接传入具体的发送者对象指针(无需转型为QObject*):
QWebEngineView view; auto waiter = SignalWaiter::Connect(&view, &QWebEngineView::loadFinished); bool signalTriggered = waiter->Wait(5000);
内容的提问来源于stack exchange,提问作者GomtheBear
相关产品推荐
相关产品推荐

