Make qReturnArg return a type templated with the return type

This way we can make check verify that the passed-in pointer is correct
at compile time.

Doesn't do this in this patch because all current uses are in the
string-based overloads, but we'll use it in a later patch which adds
new invokeMethod overloads for the functor-based API.

Change-Id: I30186adc9d0b67c7ca337deb35c2c34661e50261
Reviewed-by: Ievgenii Meshcheriakov <ievgenii.meshcheriakov@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Mårten Nordheim 2023-07-07 16:42:59 +02:00
parent 306d32fdd3
commit 777a1ed191
3 changed files with 45 additions and 36 deletions

View File

@ -1426,8 +1426,8 @@ printMethodNotFoundWarning(const QMetaObject *meta, QLatin1StringView name, qsiz
}
/*!
\fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QMetaMethodReturnArgument r, Args &&... args)
\fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, QMetaMethodReturnArgument r, Args &&... args)
\fn template <typename ReturnArg, typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<ReturnArg> r, Args &&... args)
\fn template <typename ReturnArg, typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, QTemplatedMetaMethodReturnArgument<ReturnArg> r, Args &&... args)
\fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, Args &&... args)
\fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Args &&... args)
\since 6.5
@ -1437,11 +1437,12 @@ printMethodNotFoundWarning(const QMetaObject *meta, QLatin1StringView name, qsiz
obj. Returns \c true if the member could be invoked. Returns \c false
if there is no such member or the parameters did not match.
For the overloads with a QMetaMethodReturnArgument parameter, the return
value of the \a member function call is placed in \a ret. For the overloads
without such a member, the return value of the called function (if any)
will be discarded. QMetaMethodReturnArgument is an internal type you should
not use directly. Instead, use the qReturnArg() function.
For the overloads with a QTemplatedMetaMethodReturnArgument parameter, the
return value of the \a member function call is placed in \a ret. For the
overloads without such a member, the return value of the called function
(if any) will be discarded. QTemplatedMetaMethodReturnArgument is an
internal type you should not use directly. Instead, use the qReturnArg()
function.
The overloads with a Qt::ConnectionType \a type parameter allow explicitly
selecting whether the invocation will be synchronous or not:
@ -2379,20 +2380,21 @@ QMetaMethod QMetaMethod::fromSignalImpl(const QMetaObject *metaObject, void **si
}
/*!
\fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, QMetaMethodReturnArgument ret, Args &&... arguments) const
\fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const
\fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, Args &&... arguments) const
\fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, QMetaMethodReturnArgument ret, Args &&... arguments) const
\fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invoke(QObject *obj, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const
\fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Args &&... arguments) const
\since 6.5
Invokes this method on the object \a object. Returns \c true if the member could be invoked.
Returns \c false if there is no such member or the parameters did not match.
For the overloads with a QMetaMethodReturnArgument parameter, the return
value of the \a member function call is placed in \a ret. For the overloads
without such a member, the return value of the called function (if any)
will be discarded. QMetaMethodReturnArgument is an internal type you should
not use directly. Instead, use the qReturnArg() function.
For the overloads with a QTemplatedMetaMethodReturnArgument parameter, the
return value of the \a member function call is placed in \a ret. For the
overloads without such a member, the return value of the called function
(if any) will be discarded. QTemplatedMetaMethodReturnArgument is an
internal type you should not use directly. Instead, use the qReturnArg()
function.
The overloads with a Qt::ConnectionType \a type parameter allow explicitly
selecting whether the invocation will be synchronous or not:
@ -2819,7 +2821,7 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
*/
/*!
\fn template <typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, QMetaMethodReturnArgument ret, Args &&... arguments) const
\fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const
\fn template <typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, Args &&... arguments) const
\since 6.5
@ -2830,11 +2832,11 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
The invocation is always synchronous.
For the overload with a QMetaMethodReturnArgument parameter, the return
value of the \a member function call is placed in \a ret. For the overload
without it, the return value of the called function (if any) will be
discarded. QMetaMethodReturnArgument is an internal type you should not use
directly. Instead, use the qReturnArg() function.
For the overload with a QTemplatedMetaMethodReturnArgument parameter, the
return value of the \a member function call is placed in \a ret. For the
overload without it, the return value of the called function (if any) will
be discarded. QTemplatedMetaMethodReturnArgument is an internal type you
should not use directly. Instead, use the qReturnArg() function.
\warning this method will not test the validity of the arguments: \a gadget
must be an instance of the class of the QMetaObject of which this QMetaMethod

View File

@ -135,13 +135,13 @@ public:
}
#endif
template <typename... Args>
template <typename ReturnArg, typename... Args>
#ifdef Q_QDOC
bool
#else
QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
#endif
invoke(QObject *obj, Qt::ConnectionType c, QMetaMethodReturnArgument r,
invoke(QObject *obj, Qt::ConnectionType c, QTemplatedMetaMethodReturnArgument<ReturnArg> r,
Args &&... arguments) const
{
auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...);
@ -157,16 +157,16 @@ public:
#endif
invoke(QObject *obj, Qt::ConnectionType c, Args &&... arguments) const
{
return invoke(obj, c, QMetaMethodReturnArgument{}, std::forward<Args>(arguments)...);
return invoke(obj, c, QTemplatedMetaMethodReturnArgument<void>{}, std::forward<Args>(arguments)...);
}
template <typename... Args>
template <typename ReturnArg, typename... Args>
#ifdef Q_QDOC
bool
#else
QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
#endif
invoke(QObject *obj, QMetaMethodReturnArgument r, Args &&... arguments) const
invoke(QObject *obj, QTemplatedMetaMethodReturnArgument<ReturnArg> r, Args &&... arguments) const
{
return invoke(obj, Qt::AutoConnection, r, std::forward<Args>(arguments)...);
}
@ -182,13 +182,13 @@ public:
return invoke(obj, Qt::AutoConnection, std::forward<Args>(arguments)...);
}
template <typename... Args>
template <typename ReturnArg, typename... Args>
#ifdef Q_QDOC
bool
#else
QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
#endif
invokeOnGadget(void *gadget, QMetaMethodReturnArgument r, Args &&... arguments) const
invokeOnGadget(void *gadget, QTemplatedMetaMethodReturnArgument<ReturnArg> r, Args &&... arguments) const
{
auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...);
return invokeImpl(*this, gadget, Qt::ConnectionType(-1), h.parameterCount(),
@ -203,7 +203,7 @@ public:
#endif
invokeOnGadget(void *gadget, Args &&... arguments) const
{
return invokeOnGadget(gadget, QMetaMethodReturnArgument{}, std::forward<Args>(arguments)...);
return invokeOnGadget(gadget, QTemplatedMetaMethodReturnArgument<void>{}, std::forward<Args>(arguments)...);
}
inline bool isValid() const { return mobj != nullptr; }

View File

@ -142,6 +142,12 @@ struct QMetaMethodReturnArgument
void *data;
};
template <typename T>
struct QTemplatedMetaMethodReturnArgument : QMetaMethodReturnArgument
{
using Type = T;
};
namespace QtPrivate {
namespace Invoke {
#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
@ -164,7 +170,8 @@ template <typename T> inline QMetaMethodArgument argument(const char *name, cons
}
}
template <typename T> inline QMetaMethodReturnArgument returnArgument(const char *name, T &t)
template <typename T>
inline QTemplatedMetaMethodReturnArgument<T> returnArgument(const char *name, T &t)
{
return { qMetaTypeInterfaceForType<T>(), name, std::addressof(t) };
}
@ -217,7 +224,7 @@ template <typename... Args> inline auto invokeMethodHelper(QMetaMethodReturnArgu
} // namespace QtPrivate
template <typename T> void qReturnArg(const T &&) = delete;
template <typename T> inline QMetaMethodReturnArgument qReturnArg(T &data)
template <typename T> inline QTemplatedMetaMethodReturnArgument<T> qReturnArg(T &data)
{
return QtPrivate::Invoke::returnArgument(nullptr, data);
}
@ -354,14 +361,14 @@ struct Q_CORE_EXPORT QMetaObject
}
#endif // Qt < 7.0
template <typename... Args> static
template <typename ReturnArg, typename... Args> static
#ifdef Q_QDOC
bool
#else
QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
#endif
invokeMethod(QObject *obj, const char *member, Qt::ConnectionType c,
QMetaMethodReturnArgument r, Args &&... arguments)
QTemplatedMetaMethodReturnArgument<ReturnArg> r, Args &&... arguments)
{
auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...);
return invokeMethodImpl(obj, member, c, h.parameterCount(), h.parameters.data(),
@ -376,17 +383,17 @@ struct Q_CORE_EXPORT QMetaObject
#endif
invokeMethod(QObject *obj, const char *member, Qt::ConnectionType c, Args &&... arguments)
{
QMetaMethodReturnArgument r = {};
QTemplatedMetaMethodReturnArgument<void> r = {};
return invokeMethod(obj, member, c, r, std::forward<Args>(arguments)...);
}
template <typename... Args> static
template <typename ReturnArg, typename... Args> static
#ifdef Q_QDOC
bool
#else
QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
#endif
invokeMethod(QObject *obj, const char *member, QMetaMethodReturnArgument r,
invokeMethod(QObject *obj, const char *member, QTemplatedMetaMethodReturnArgument<ReturnArg> r,
Args &&... arguments)
{
return invokeMethod(obj, member, Qt::AutoConnection, r, std::forward<Args>(arguments)...);
@ -400,7 +407,7 @@ struct Q_CORE_EXPORT QMetaObject
#endif
invokeMethod(QObject *obj, const char *member, Args &&... arguments)
{
QMetaMethodReturnArgument r = {};
QTemplatedMetaMethodReturnArgument<void> r = {};
return invokeMethod(obj, member, Qt::AutoConnection, r, std::forward<Args>(arguments)...);
}