Constrain QCoreApplication::requestPermission to compatible functors

The 6.5 versions of the overload not taking a context/receiver object
were constrained by requiring a functor to be free function or lambda.
207aae5560aa2865ec55ddb9ecbb50048060c0c0 removed that constraint, which
might be source incomaptible if wrapper functions in user code forward
the constraint using Expression SFINAE. Those wrappers would no longer
be removed from the overload set based on the same criteria as the
function they wrap.

We can't constrain the new functions based on the same predicate as
before, as after the simplification we have only one overload with, and
one without context object. But we can still remove overloads for
incompatible functors.

Add the respective scenario to the QPermission test as a compile-time
test.

Found during 6.6 header review.

Change-Id: Id21391b4a6b78a29de2f8fa04374f4262e5fafa7
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
(cherry picked from commit d027b0c8162ac888de233cf3a41e3254ba2d7cc8)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Volker Hilsheimer 2023-08-22 18:48:48 +02:00 committed by Qt Cherry-pick Bot
parent 50d9ed401b
commit fbafac20af
2 changed files with 37 additions and 5 deletions

View File

@ -60,6 +60,10 @@ class Q_CORE_EXPORT QCoreApplication
Q_DECLARE_PRIVATE(QCoreApplication)
friend class QEventLoopLocker;
#if QT_CONFIG(permissions)
using RequestPermissionPrototype = void(*)(QPermission);
#endif
public:
enum { ApplicationFlags = QT_VERSION
};
@ -122,21 +126,25 @@ public:
# else
// requestPermission with context or receiver object; need to require here that receiver is the
// right type to avoid ambiguity with the private implementation function.
template <typename Functor>
template <typename Functor,
std::enable_if_t<
QtPrivate::AreFunctionsCompatible<RequestPermissionPrototype, Functor>::value,
bool> = true>
void requestPermission(const QPermission &permission,
const typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType *receiver,
Functor &&func)
{
using Prototype = void(*)(QPermission);
QtPrivate::AssertCompatibleFunctions<Prototype, Functor>();
requestPermission(permission,
QtPrivate::makeCallableObject<Prototype>(std::forward<Functor>(func)),
QtPrivate::makeCallableObject<RequestPermissionPrototype>(std::forward<Functor>(func)),
receiver);
}
# endif // Q_QDOC
// requestPermission to a functor or function pointer (without context)
template <typename Functor>
template <typename Functor,
std::enable_if_t<
QtPrivate::AreFunctionsCompatible<RequestPermissionPrototype, Functor>::value,
bool> = true>
void requestPermission(const QPermission &permission, Functor &&func)
{
requestPermission(permission, nullptr, std::forward<Functor>(func));

View File

@ -146,6 +146,19 @@ void tst_QPermission::conversionMaintainsState() const
}
}
template <typename Func,
typename T = std::void_t<decltype(qApp->requestPermission(std::declval<DummyPermission>(),
std::declval<Func>()))>
>
void wrapRequestPermission(const QPermission &p, Func &&f)
{
qApp->requestPermission(p, std::forward<Func>(f));
}
template <typename Functor>
using CompatibleTest = decltype(wrapRequestPermission(std::declval<QPermission>(), std::declval<Functor>()));
// Compile test for context-less functor overloads
void tst_QPermission::functorWithoutContext()
{
@ -161,6 +174,17 @@ void tst_QPermission::functorWithoutContext()
qApp->requestPermission(dummy, [](const QPermission &permission){
QVERIFY(permission.value<DummyPermission>());
});
wrapRequestPermission(dummy, [](const QPermission &permission){
QVERIFY(permission.value<DummyPermission>());
});
auto compatible = [](const QPermission &) {};
using Compatible = decltype(compatible);
auto incompatible = [](const QString &) {};
using Incompatible = decltype(incompatible);
static_assert(qxp::is_detected_v<CompatibleTest, Compatible>);
static_assert(!qxp::is_detected_v<CompatibleTest, Incompatible>);
}
void tst_QPermission::functorWithContextInThread()