首页 > 其他分享 >新版本QT的QMetaObject::invokeMethod实现

新版本QT的QMetaObject::invokeMethod实现

时间:2024-09-20 11:03:20浏览次数:9  
标签:std return QT QMetaObject template invokeMethod const type

corelib\kernel\qobjectdefs.h   

template <typename T>
inline QTemplatedMetaMethodReturnArgument<T> returnArgument(const char *name, T &t)
{
    return { qMetaTypeInterfaceForType<T>(), name, std::addressof(t) };
}

template <typename T> inline const char *typenameHelper(const T &)
{
    return nullptr;
}
template <typename T> inline const void *dataHelper(const T &t)
{
    return std::addressof(t);
}
template <typename T> inline const QMetaTypeInterface *metaTypeHelper(const T &)
{
    return qMetaTypeInterfaceForType<T>();
}

struct QMetaMethodReturnArgument
{
    const QtPrivate::QMetaTypeInterface *metaType;
    const char *name;
    void *data;
};

template <typename T>
struct QTemplatedMetaMethodReturnArgument : QMetaMethodReturnArgument
{
    using Type = T;
};

template <typename Func, typename... Args>
  static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
                                              QtPrivate::Invoke::AreOldStyleArgs<Args...>>,
                          bool>
  invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
               Func &&function, Qt::ConnectionType type,
               QTemplatedMetaMethodReturnArgument<
                       typename QtPrivate::Callable<Func, Args...>::ReturnType>
                       ret,
               Args &&...args)
  {
      return invokeMethodCallableHelper(object, std::forward<Func>(function), type, ret,
                                        std::forward<Args>(args)...);
  }



  template <typename Func, typename... Args>
  static bool
  invokeMethodCallableHelper(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
          Func &&function, Qt::ConnectionType type, const QMetaMethodReturnArgument &ret,
          Args &&...args)
  {
      using Callable = QtPrivate::Callable<Func, Args...>;
      using ExpectedArguments = typename Callable::Arguments;
      static_assert(sizeof...(Args) <= ExpectedArguments::size, "Too many arguments");
      using ActualArguments = QtPrivate::List<Args...>;
      static_assert(QtPrivate::CheckCompatibleArguments<ActualArguments,
                            ExpectedArguments>::value,
              "Incompatible arguments");

      auto h = QtPrivate::invokeMethodHelper(ret, args...);

      // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
      auto callable = new QtPrivate::QCallableObject<std::decay_t<Func>, ActualArguments,
              typename Callable::ReturnType>(std::forward<Func>(function));
      return invokeMethodImpl(object, callable, type, h.parameterCount(), h.parameters.data(),
              h.typeNames.data(), h.metaTypes.data());
  }


template <typename... Args> inline auto invokeMethodHelper(QMetaMethodReturnArgument r, const Args &... arguments)
{
    std::array params = { const_cast<const void *>(r.data), Invoke::dataHelper(arguments)... };
    std::array names = { r.name, Invoke::typenameHelper(arguments)... };
    std::array types = { r.metaType, Invoke::metaTypeHelper(arguments)... };
    static_assert(params.size() == types.size());
    static_assert(params.size() == names.size());

    struct R {
        decltype(params) parameters;
        decltype(names) typeNames;
        decltype(types) metaTypes;
        constexpr qsizetype parameterCount() const { return qsizetype(parameters.size()); }
    };
    return R { params, names, types };
}
} // namespace QtPrivate


corelib\kernel\qmetaobject.cpp

bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
                                qsizetype parameterCount, const void *const *params, const char *const *names,
                                const QtPrivate::QMetaTypeInterface * const *metaTypes)
{
    // We don't need this now but maybe we want it later, or we may be able to
    // share more code between the two invokeMethodImpl() overloads:
    Q_UNUSED(names);
    auto slot = QtPrivate::SlotObjUniquePtr(slotObj);

    if (! object) // ### only if the slot requires the object + not queued?
        return false;

    Qt::HANDLE currentThreadId = QThread::currentThreadId();
    QThread *objectThread = object->thread();
    bool receiverInSameThread = false;
    if (objectThread)
        receiverInSameThread = currentThreadId == QThreadData::get2(objectThread)->threadId.loadRelaxed();

    if (type == Qt::AutoConnection)
        type = receiverInSameThread ? Qt::DirectConnection : Qt::QueuedConnection;

    void **argv = const_cast<void **>(params);
    if (type == Qt::DirectConnection) {
        slot->call(object, argv);
    } else if (type == Qt::QueuedConnection) {
        if (argv[0]) {
            qWarning("QMetaObject::invokeMethod: Unable to invoke methods with return values in "
                     "queued connections");
            return false;
        }
        auto event = std::make_unique<QMetaCallEvent>(std::move(slot), nullptr, -1, parameterCount);
        void **args = event->args();
        QMetaType *types = event->types();

        for (int i = 1; i < parameterCount; ++i) {
            types[i] = QMetaType(metaTypes[i]);
            args[i] = types[i].create(argv[i]);
        }

        QCoreApplication::postEvent(object, event.release());
    } else if (type == Qt::BlockingQueuedConnection) {
#if QT_CONFIG(thread)
        if (receiverInSameThread)
            qWarning("QMetaObject::invokeMethod: Dead lock detected");

        QSemaphore semaphore;
        QCoreApplication::postEvent(object, new QMetaCallEvent(std::move(slot), nullptr, -1, argv, &semaphore));
        semaphore.acquire();
#endif // QT_CONFIG(thread)
    } else {
        qWarning("QMetaObject::invokeMethod: Unknown connection type");
        return false;
    }
    return true;
}



corelib\kernel\qmetatype.h

template<typename T>
constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType()
{
    // don't check the type is suitable here
    using Ty = typename MetatypeDecay<T>::type;
    return &QMetaTypeInterfaceWrapper<Ty>::metaType;
}

template<typename T>
struct QMetaTypeInterfaceWrapper
{
    // if the type ID for T is known at compile-time, then we can declare
    // the QMetaTypeInterface object const; otherwise, we declare it as
    // non-const and the .typeId is updated by QMetaType::idHelper().
    static constexpr bool IsConstMetaTypeInterface = !!BuiltinMetaType<T>::value;
    using InterfaceType = std::conditional_t<IsConstMetaTypeInterface, const QMetaTypeInterface, NonConstMetaTypeInterface>;

    static inline InterfaceType metaType = {
        /*.revision=*/ QMetaTypeInterface::CurrentRevision,
        /*.alignment=*/ alignof(T),
        /*.size=*/ sizeof(T),
        /*.flags=*/ QMetaTypeForType<T>::Flags,
        /*.typeId=*/ BuiltinMetaType<T>::value,
        /*.metaObjectFn=*/ MetaObjectForType<T>::metaObjectFunction,
        /*.name=*/ QMetaTypeForType<T>::getName(),
        /*.defaultCtr=*/ QMetaTypeForType<T>::getDefaultCtr(),
        /*.copyCtr=*/ QMetaTypeForType<T>::getCopyCtr(),
        /*.moveCtr=*/ QMetaTypeForType<T>::getMoveCtr(),
        /*.dtor=*/ QMetaTypeForType<T>::getDtor(),
        /*.equals=*/ QEqualityOperatorForType<T>::equals,
        /*.lessThan=*/ QLessThanOperatorForType<T>::lessThan,
        /*.debugStream=*/ QDebugStreamOperatorForType<T>::debugStream,
        /*.dataStreamOut=*/ QDataStreamOperatorForType<T>::dataStreamOut,
        /*.dataStreamIn=*/ QDataStreamOperatorForType<T>::dataStreamIn,
        /*.legacyRegisterOp=*/ QMetaTypeForType<T>::getLegacyRegister()
    };
};

template<typename T, typename = void>
struct BuiltinMetaType : std::integral_constant<int, 0>
{
};
template<typename T>
struct BuiltinMetaType<T, std::enable_if_t<QMetaTypeId2<T>::IsBuiltIn>>
    : std::integral_constant<int, QMetaTypeId2<T>::MetaType>
{
};

template <typename T>
struct QMetaTypeId2
{
    using NameAsArrayType = void;
    enum { Defined = QMetaTypeId<T>::Defined, IsBuiltIn=false };
    static inline constexpr int qt_metatype_id() { return QMetaTypeId<T>::qt_metatype_id(); }
};

template <typename T>
struct QMetaTypeId2<const T&> : QMetaTypeId2<T> {};

template <typename T>
struct QMetaTypeId2<T&>
{
    using NameAsArrayType = void;
    enum { Defined = false, IsBuiltIn = false };
    static inline constexpr int qt_metatype_id() { return 0; }
};

#define Q_DECLARE_BUILTIN_METATYPE(TYPE, METATYPEID, NAME) \
    QT_BEGIN_NAMESPACE \
    template<> struct QMetaTypeId2<NAME> \
    { \
        using NameAsArrayType = std::array<char, sizeof(#NAME)>; \
        enum { Defined = 1, IsBuiltIn = true, MetaType = METATYPEID };   \
        static inline constexpr int qt_metatype_id() { return METATYPEID; } \
        static constexpr NameAsArrayType nameAsArray = { #NAME }; \
    }; \
    QT_END_NAMESPACE





QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE)

#define QT_FOR_EACH_STATIC_TYPE(F)\
    QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
    QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(F)\
    QT_FOR_EACH_STATIC_CORE_CLASS(F)\
    QT_FOR_EACH_STATIC_CORE_POINTER(F)\
    QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
    QT_FOR_EACH_STATIC_GUI_CLASS(F)\
    QT_FOR_EACH_STATIC_WIDGETS_CLASS(F)\

#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)        \
    QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(F)   \
    F(Void, 43, void) \

#define QT_FOR_EACH_STATIC_PRIMITIVE_NON_VOID_TYPE(F)\
    F(Bool, 1, bool) \
    F(Int, 2, int) \
    F(UInt, 3, uint) \
    F(LongLong, 4, qlonglong) \
    F(ULongLong, 5, qulonglong) \
    F(Double, 6, double) \
    F(Long, 32, long) \
    F(Short, 33, short) \
    F(Char, 34, char) \
    F(Char16, 56, char16_t) \
    F(Char32, 57, char32_t) \
    F(ULong, 35, ulong) \
    F(UShort, 36, ushort) \
    F(UChar, 37, uchar) \
    F(Float, 38, float) \
    F(SChar, 40, signed char) \
    F(Nullptr, 51, std::nullptr_t) \
    F(QCborSimpleType, 52, QCborSimpleType) \

标签:std,return,QT,QMetaObject,template,invokeMethod,const,type
From: https://www.cnblogs.com/DesertCactus/p/18422074

相关文章

  • Qt::BlockingQueuedConnection 与 QMetaCallEvent
    Qt创建连接类型如果是Qt::BlockingQueuedConnection,即senderthread与receiverthread不同,但是要求sendersignal与receiverslot执行是不同线程间的同步行为。也即:在sendersignal发出后sender线程要等待receiver线程的slot执行完后才能继续向后执行指令。......
  • PyQt5 使用 QStackedWidget 实现轮播展示动画(自动与手动)
    PyQt5使用QStackedWidget实现轮播展示动画(自动与手动)在PyQt5中,如果需要用QStackedWidget展示图片比较生硬,参考网络上的一些内容,发现用QPropertyAnimation属性动画可实现想要的效果,于是记录在这里代码结构本文中全部代码全在test_QStackedWidget_Animation.py这一个文件中......
  • Qt Create多核编译配置
    随着qt项目的不断增大,项目编译的速度就越来越慢了,那么怎么解决编译项目慢的问题的呢?方法有二。方法1:该方法修改只对该项目有效。在Makearguments:填写-j4表示CPU使用4个核进行代码编译。方法2:该方法可以使用于所有项目编译。在Qtcreate的菜单栏点击"工具"--->"选项"-......
  • Qt 事件处理
    classQtWidgetsApplication1:publicQMainWindow{Q_OBJECTpublic:QtWidgetsApplication1(QWidget*parent=nullptr);~QtWidgetsApplication1();private:Ui::QtWidgetsApplication1Classui;publicslots:voidchangelabel();};QtWi......
  • PyQt / PySide + Pywin32 + ctypes 自定义标题栏窗口 + 完全还原 Windows 原生窗口边
    项目地址:GitHub-github201014/PyQt-NativeWindow:AclassofwindowincludenativeEvent,usePySideorPyQtandPywin32andctypesAclassofwindowincludenativeEvent,usePySideorPyQtandPywin32andctypes-github201014/PyQt-NativeWindowhttps://githu......
  • MQTT mosquitto, centos mosquitto[24330]: 1726226300: Socket error on client <unk
    Sep1319:18:20VM-8-12-centosmosquitto[24330]:1726226300:Socketerroronclient<unknown>,disconnecting.报错解释:这个错误来自于在CentOS系统上运行的MosquittoMQTT代理。错误信息表明客户端在尝试与Mosquitto通信时遇到了套接字错误(Socketerror),错误后面的数字可能是......
  • Qt 模型视图(四):代理类QAbstractItemDelegate
    文章目录Qt模型视图(四):代理类`QAbstractItemDelegate`1.基本概念1.1.使用现有代理1.2.一个简单的代理2.提供编辑器3.向模型提交数据4.更新编辑器的几何图形5.编辑提示Qt模型视图(四):代理类QAbstractItemDelegate​模型/视图结构是一种将数据存储和界面展示分......
  • Qt加载天地图离线api开发包/从官网趴地图js代码/费了九牛二虎之力终于搞定
    一、前言说明网上关于如何趴天地图离线api文件的文章,只有少量的两三篇,而且几乎没有说全和说对,搞得评论也是一片懵逼,这里不行那你不行,思路可以借鉴就是。索性花了点时间,自己研究了如何从官网一步步趴下来js文件,最终所有离线能使用的功能全部搞定,也根本不会有http等访问的情况出现,......
  • Qt:实现单例模式
    前言记录一下。正文单例模式根据实现方式和应用场景在Qt中可以分为以下几种类型:1.懒汉式单例懒汉式单例在第一次使用时才创建实例,延迟了对象的初始化。懒汉式单例分为线程安全和线程不安全两种实现方式。线程不安全的懒汉式单例:在第一次调用getInstance()时创建......
  • Qt Metadata
    1.codeclassGranPa:publicQObject{Q_OBJECTpublic:explicitGranPa(QObject*parent=nullptr);signals:voidgran_siga();voidgran_sigb();voidgran_sigc();publicslots:voidgran_slota();voidgran_slotb();voidgran_slotc();};GranPa::GranPa(QOb......