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