Qt connect函数 functor 的使用

1. QObject::connect  经典方式是 字符串 链接

声明:

static QMetaObject::Connection connect(
                      const QObject *sender, const char *signal, 
                     const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection ); 

connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));

信号(Signal) 槽(Slot) 链接 使用  主要  有两种:

    template<typename PointerToMemberFunction, typename Functor>
    static QMetaObject::Connection connect
             ( const QObject *sender, PointerToMemberFunction signal, 
               Functor functor);

    template<typename PointerToMemberFunction, typename Functor>
    static QMetaObject::Connection connect
             (const QObject *sender, PointerToMemberFunction signal, 
              const QObject *context, Functor functor, 
              Qt::ConnectionType type = Qt::AutoConnection);

1. 提供 const QObject *receiver 参数

2. 没有  const QObject *receiver 参数

注意: 上面的形式 是方便C++用户理解使用的语法形式。 也是QT文档使用的形式(Q_DOC)

             内部实现的代码是下面的形式。

参看实现  可知: 如果没有 提供 const QObject *receiver 参数, 则使用 sender.

    //connect to a functor
    template <typename Func1, typename Func2>
    static inline typename std::enable_if<
          QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, 
          QMetaObject::Connection>::type
    connect( const typename QtPrivate::FunctionPointer<Func1>::Object *sender, 
             Func1 signal, 
             Func2 slot)
    {
        return connect(sender, signal, sender, slot, Qt::DirectConnection);
    } 
template <typename Func1, typename Func2>

static inline QMetaObject::Connection connect(
    const typename QtPrivate::FunctionPointer<Func1>::Object *sender, 
    Func1 signal,
    const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, 
    Func2 slot,
    Qt::ConnectionType type = Qt::AutoConnection)

对于类的成员函数, 使用的是 模板进行解析,利用的是模板的参数匹配功能,使用的语法解析:

    template<class Obj, typename Ret, typename... Args> 
    struct FunctionPointer<Ret (Obj::*) (Args...)>

    {
        typedef Obj Object;
        typedef List<Args...>  Arguments;
        typedef Ret ReturnType;
        typedef Ret (Obj::*Function) (Args...);
        enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
        template <typename SignalArgs, typename R>
        static void call(Function f, Obj *o, void **arg) 
        {
            FunctorCall<
                typename Indexes<ArgumentCount>::Value, 
                SignalArgs, R, 
                Function>
            ::call(f, o, arg);
        }
    };

利用这个模板 将 ClassName::MemberFunction 的函数  分离出:

    Object:   ClassName

   ReturnType  Ret

  Arguments    参数列表

函数调用 和参数传递

void TestSigObj::sglClass(ClassParam _t1, const QString _t2)
{
    void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)) };
    QMetaObject::activate(this, &staticMetaObject, 1, _a);
}
void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
{
    int signal_index = signalOffset + local_signal_index;


    void *empty_argv[] = { 0 };
    if (qt_signal_spy_callback_set.signal_begin_callback != 0) {
        qt_signal_spy_callback_set.signal_begin_callback(sender, signal_index,
                                                         argv ? argv : empty_argv);
    }

    {
    QMutexLocker locker(signalSlotLock(sender));

    ConnectionListsRef connectionLists = sender->d_func()->connectionLists;
    if (!connectionLists.connectionLists) {
        locker.unlock();
        if (qt_signal_spy_callback_set.signal_end_callback != 0)
            qt_signal_spy_callback_set.signal_end_callback(sender, signal_index);
        return;
    }

    const QObjectPrivate::ConnectionList *list;
    if (signal_index < connectionLists->count())
        list = &connectionLists->at(signal_index);
    else
        list = &connectionLists->allsignals;

    Qt::HANDLE currentThreadId = QThread::currentThreadId();

    do {
        QObjectPrivate::Connection *c = list->first;
        if (!c) continue;
        // We need to check against last here to ensure that signals added
        // during the signal emission are not emitted in this emission.
        QObjectPrivate::Connection *last = list->last;

        do {
            if (!c->receiver)
                continue;

            QObject * const receiver = c->receiver;
            const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId.load();

            // determine if this connection should be sent immediately or
            // put into the event queue
            if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
                || (c->connectionType == Qt::QueuedConnection)) {
                queued_activate(sender, signal_index, c, argv ? argv : empty_argv, locker);
                continue;
#ifndef QT_NO_THREAD
            } else if (c->connectionType == Qt::BlockingQueuedConnection) {
                if (receiverInSameThread) {
                    qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
                    "Sender is %s(%p), receiver is %s(%p)",
                    sender->metaObject()->className(), sender,
                    receiver->metaObject()->className(), receiver);
                }
                QSemaphore semaphore;
                QMetaCallEvent *ev = c->isSlotObject ?
                    new QMetaCallEvent(c->slotObj, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore) :
                    new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore);
                QCoreApplication::postEvent(receiver, ev);
                locker.unlock();
                semaphore.acquire();
                locker.relock();
                continue;
#endif
            }

            QConnectionSenderSwitcher sw;

            if (receiverInSameThread) {
                sw.switchSender(receiver, sender, signal_index);
            }
            if (c->isSlotObject) {
                c->slotObj->ref();
                QScopedPointer<QtPrivate::QSlotObjectBase, QSlotObjectBaseDeleter> obj(c->slotObj);
                locker.unlock();
                obj->call(receiver, argv ? argv : empty_argv);

                // Make sure the slot object gets destroyed before the mutex is locked again, as the
                // destructor of the slot object might also lock a mutex from the signalSlotLock() mutex pool,
                // and that would deadlock if the pool happens to return the same mutex.
                obj.reset();

                locker.relock();
            } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
                //we compare the vtable to make sure we are not in the destructor of the object.
                const int methodIndex = c->method();
                const int method_relative = c->method_relative;
                const auto callFunction = c->callFunction;
                locker.unlock();
                if (qt_signal_spy_callback_set.slot_begin_callback != 0)
                    qt_signal_spy_callback_set.slot_begin_callback(receiver, methodIndex, argv ? argv : empty_argv);

                callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv);

                if (qt_signal_spy_callback_set.slot_end_callback != 0)
                    qt_signal_spy_callback_set.slot_end_callback(receiver, methodIndex);
                locker.relock();
            } else {
                const int method = c->method_relative + c->method_offset;
                locker.unlock();

                if (qt_signal_spy_callback_set.slot_begin_callback != 0) {
                    qt_signal_spy_callback_set.slot_begin_callback(receiver,
                                                                method,
                                                                argv ? argv : empty_argv);
                }

                metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);

                if (qt_signal_spy_callback_set.slot_end_callback != 0)
                    qt_signal_spy_callback_set.slot_end_callback(receiver, method);

                locker.relock();
            }

            if (connectionLists->orphaned)
                break;
        } while (c != last && (c = c->nextConnectionList) != 0);

        if (connectionLists->orphaned)
            break;
    } while (list != &connectionLists->allsignals &&
        //start over for all signals;
        ((list = &connectionLists->allsignals), true));

    }

    if (qt_signal_spy_callback_set.signal_end_callback != 0)
        qt_signal_spy_callback_set.signal_end_callback(sender, signal_index);

}

same thread

                QScopedPointer<QtPrivate::QSlotObjectBase, QSlotObjectBaseDeleter> obj(c->slotObj);
                locker.unlock();
                obj->call(receiver, argv ? argv : empty_argv);
        inline void call(QObject *r, void **a)  { m_impl(Call,    this, r, a, Q_NULLPTR); }

    template<typename Func, int N, typename Args, typename R> class QFunctorSlotObject : public QSlotObjectBase
    {
        typedef QtPrivate::Functor<Func, N> FuncType;
        Func function;
        static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
        {
            switch (which) {
            case Destroy:
                delete static_cast<QFunctorSlotObject*>(this_);
                break;
            case Call:
                FuncType::template call<Args, R>(static_cast<QFunctorSlotObject*>(this_)->function, r, a);
                break;
            case Compare: // not implemented
            case NumOperations:
                Q_UNUSED(ret);
            }
        }
    public:
        explicit QFunctorSlotObject(const Func &f) : QSlotObjectBase(&impl), function(f) {}
    };

    template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
    struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...)> {
        static void call(SlotRet (Obj::*f)(SlotArgs...), Obj *o, void **arg) {
            (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
        }
    };

2. QTimer::singleShot

支持  lamda  functor.  也有两种形式

 没有  const QObject *receiver 参数 的 实现:

    // singleShot to a functor or function pointer (without context)
    template <typename Duration, typename Func1>
    static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
                                          !std::is_same<const char*, Func1>::value, void>::type
            singleShot(Duration interval, Func1 slot)
    {
        singleShot(interval, defaultTypeFor(interval), nullptr, slot);
    }

可知:  如果没有 提供 const QObject *receiver 参数, 和  QObject::connect 不同的是 使用 nullptr.

receiver  == nullptr  处理函数 是在那个 执行线程  中呢  ? 

实现:

void QTimer::singleShotImpl(int msec, Qt::TimerType timerType,
                            const QObject *receiver,
                            QtPrivate::QSlotObjectBase *slotObj)
{
    new QSingleShotTimer(msec, timerType, receiver, slotObj);
}

QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, QtPrivate::QSlotObjectBase *slotObj)
    : QObject(QAbstractEventDispatcher::instance()), hasValidReceiver(r), receiver(r), slotObj(slotObj)
{
    timerId = startTimer(msec, timerType);
    if (r && thread() != r->thread()) {
        // Avoid leaking the QSingleShotTimer instance in case the application exits before the timer fires
        connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QObject::deleteLater);
        setParent(0);
        moveToThread(r->thread());
    }
}

可知:  如果 receiver == nullptr,  父对象是: QAbstractEventDispatcher::instance()

static QAbstractEventDispatcher *instance(QThread *thread = Q_NULLPTR);

QAbstractEventDispatcher *QAbstractEventDispatcher::instance(QThread *thread)
{
    QThreadData *data = thread ? QThreadData::get2(thread) : QThreadData::current();
    return data->eventDispatcher.load();
}

执行 startTimer 语句, 则会在创建Timer的线程事件队列处理。

void QSingleShotTimer::timerEvent(QTimerEvent *)
{
    // need to kill the timer _before_ we emit timeout() in case the
    // slot connected to timeout calls processEvents()
    if (timerId > 0)
        killTimer(timerId);
    timerId = -1;

    if (slotObj) {
        // If the receiver was destroyed, skip this part
        if (Q_LIKELY(!receiver.isNull() || !hasValidReceiver)) {
            // We allocate only the return type - we previously checked the function had
            // no arguments.
            void *args[1] = { 0 };
            slotObj->call(const_cast<QObject*>(receiver.data()), args);
        }
    } else {
        emit timeout();
    }


}

3. QTimer  

若没有指定 对象 持有者, 则在 当前的执行线程(即  创建这个QTimer 的线程 )中, 启动 timer.

slot 调用流程 (slot 是 Lamda)

    template <int... II, typename... SignalArgs, typename R, typename Function>
    struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, Function> {
        static void call(Function &f, void **arg) {
            f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
        }
    };

arg:   是原始 堆栈列表

slot 是函数,  调用的形式:

    template <int... II, typename... SignalArgs, 
              typename R, typename... SlotArgs, typename SlotRet, 
              class Obj>
    struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, 
                      SlotRet (Obj::*)(SlotArgs...)> 
    {
        static void call(SlotRet (Obj::*f)(SlotArgs...), Obj *o, void **arg)
        {
            (o->*f)(
           (*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...),
           ApplyReturnValue<R>(arg[0]);
        }
    };

类型的校验 是模板参数编译时执行:

        Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<
typename SignalType::Arguments, 
typename SlotType::Arguments>::value),
                          "Signal and slot arguments are not compatible.");


    struct CheckCompatibleArguments<List<Arg1, Tail1...>, List<Arg2, Tail2...>>
    {
        enum { 
value = AreArgumentsCompatible<
    typename RemoveConstRef<Arg1>::Type, typename RemoveConstRef<Arg2>::Type>::value
 && CheckCompatibleArguments<List<Tail1...>, List<Tail2...>>::value };
    };

    struct CheckCompatibleArguments<List<Arg1, Tail1...>, List<Arg2, Tail2...>>
    {
        enum { value = AreArgumentsCompatible<typename RemoveConstRef<Arg1>::Type, typename RemoveConstRef<Arg2>::Type>::value
                    && CheckCompatibleArguments<List<Tail1...>, List<Tail2...>>::value };
    };

class IHHUserActionManager {
public:
    ~IHHUserActionManager(){}
    virtual QObject *getObject() = 0;
    virtual bool initUserActionAppInfo(QString appKey,QString appName,QString appVersion)=0;
    virtual void setUid(QString uid)=0;
    virtual void setUploadSize(int uploadSize)=0;
    virtual void AddActionByQueue(QString eventid,QJsonObject customJsonContent)= 0;
    virtual void AddActionByQueue(QJsonObject ActionObject)= 0;
    virtual void AddActionByQueue(QString eventid,QString customJsonContent)= 0;
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值