Search code examples
c++qtc++11templatesqt5

Qt template function(or constructor) for signal (C++)


I wanted to create a class waiting for Signal so I could connect all the signals.

But the template function doesn't seem to know the type of signal.

I tried this code:

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>
inline std::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();
}

I wrote the code like this, but I get a compilation error in the part I use:

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)
        ]

Why is there such an error? Can't the template get the signal type?

note: I also tried template constructor (Because I thought Func would be deduced):

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>
inline SignalWaiter::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();
}

I am sorry for my poor English.


Solution

  • If Func isn't a QObject member-function pointer, the connection can't be made. You need to deduce the source object type too:

        template<typename Sender, typename Func>
        static std::unique_ptr<SignalWaiter> Connect(Sender* sender, Func signal);