Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-17 09:17:29

0001 // Copyright (C) 2016 The Qt Company Ltd.
0002 // Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
0003 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0004 // Qt-Security score:significant reason:default
0005 
0006 #ifndef QOBJECTDEFS_H
0007 #error Do not include qobjectdefs_impl.h directly
0008 #include <QtCore/qnamespace.h>
0009 #endif
0010 
0011 #if 0
0012 #pragma qt_sync_skip_header_check
0013 #pragma qt_sync_stop_processing
0014 #endif
0015 
0016 #include <QtCore/qfunctionaltools_impl.h>
0017 
0018 #include <memory>
0019 
0020 QT_BEGIN_NAMESPACE
0021 class QObject;
0022 class QObjectPrivate;
0023 class QMetaMethod;
0024 class QByteArray;
0025 
0026 namespace QtPrivate {
0027     template <typename T> struct RemoveRef { typedef T Type; };
0028     template <typename T> struct RemoveRef<T&> { typedef T Type; };
0029     template <typename T> struct RemoveConstRef { typedef T Type; };
0030     template <typename T> struct RemoveConstRef<const T&> { typedef T Type; };
0031 
0032     /*
0033        The following List classes are used to help to handle the list of arguments.
0034        It follow the same principles as the lisp lists.
0035        List_Left<L,N> take a list and a number as a parameter and returns (via the Value typedef,
0036        the list composed of the first N element of the list
0037      */
0038     // With variadic template, lists are represented using a variadic template argument instead of the lisp way
0039     template <typename... Ts> struct List { static constexpr size_t size = sizeof...(Ts); };
0040     template<typename T> struct SizeOfList { static constexpr size_t value = 1; };
0041     template<> struct SizeOfList<List<>> { static constexpr size_t value = 0; };
0042     template<typename ...Ts> struct SizeOfList<List<Ts...>>  { static constexpr size_t value = List<Ts...>::size; };
0043     template <typename Head, typename... Tail> struct List<Head, Tail...> {
0044         static constexpr size_t size = 1 + sizeof...(Tail);
0045         typedef Head Car; typedef List<Tail...> Cdr;
0046     };
0047     template <typename, typename> struct List_Append;
0048     template <typename... L1, typename...L2> struct List_Append<List<L1...>, List<L2...>> { typedef List<L1..., L2...> Value; };
0049     template <typename L, int N> struct List_Left {
0050         typedef typename List_Append<List<typename L::Car>,typename List_Left<typename L::Cdr, N - 1>::Value>::Value Value;
0051     };
0052     template <typename L> struct List_Left<L, 0> { typedef List<> Value; };
0053 
0054     /*
0055         This is used to store the return value from a slot, whether the caller
0056         wants to store this value (QMetaObject::invokeMethod() with
0057         qReturnArg() or non-void signal ) or not.
0058      */
0059     struct FunctorCallBase
0060     {
0061         template <typename R, typename Lambda>
0062         static void call_internal([[maybe_unused]] void **args, Lambda &&fn)
0063             noexcept(std::is_nothrow_invocable_v<Lambda>)
0064         {
0065             if constexpr (std::is_void_v<R> || std::is_void_v<std::invoke_result_t<Lambda>>) {
0066                 std::forward<Lambda>(fn)();
0067             } else {
0068                 if (args[0])
0069                     *reinterpret_cast<R *>(args[0]) = std::forward<Lambda>(fn)();
0070                 else
0071                     [[maybe_unused]] auto r = std::forward<Lambda>(fn)();
0072             }
0073         }
0074     };
0075 
0076     /*
0077       The FunctionPointer<Func> struct is a type trait for function pointer.
0078         - ArgumentCount  is the number of argument, or -1 if it is unknown
0079         - the Object typedef is the Object of a pointer to member function
0080         - the Arguments typedef is the list of argument (in a QtPrivate::List)
0081         - the Function typedef is an alias to the template parameter Func
0082         - the call<Args, R>(f,o,args) method is used to call that slot
0083             Args is the list of argument of the signal
0084             R is the return type of the signal
0085             f is the function pointer
0086             o is the receiver object
0087             and args is the array of pointer to arguments, as used in qt_metacall
0088 
0089        The Functor<Func,N> struct is the helper to call a functor of N argument.
0090        Its call function is the same as the FunctionPointer::call function.
0091      */
0092     template<typename Func> struct FunctionPointer { enum {ArgumentCount = -1, IsPointerToMemberFunction = false}; };
0093 
0094     template<typename ObjPrivate> inline void assertObjectType(QObjectPrivate *d);
0095     template<typename Obj> inline void assertObjectType(QObject *o)
0096     {
0097         // ensure all three compile
0098         [[maybe_unused]] auto staticcast = [](QObject *obj) { return static_cast<Obj *>(obj); };
0099         [[maybe_unused]] auto qobjcast = [](QObject *obj) { return Obj::staticMetaObject.cast(obj); };
0100 #ifdef __cpp_rtti
0101         [[maybe_unused]] auto dyncast = [](QObject *obj) { return dynamic_cast<Obj *>(obj); };
0102         auto cast = dyncast;
0103 #else
0104         auto cast = qobjcast;
0105 #endif
0106         Q_ASSERT_X(cast(o), Obj::staticMetaObject.className(),
0107                    "Called object is not of the correct type (class destructor may have already run)");
0108     }
0109 
0110     template <typename, typename, typename, typename> struct FunctorCall;
0111     template <size_t... II, typename... SignalArgs, typename R, typename Function>
0112     struct FunctorCall<std::index_sequence<II...>, List<SignalArgs...>, R, Function> : FunctorCallBase
0113     {
0114         static void call(Function &f, void **arg)
0115         {
0116             call_internal<R>(arg, [&] {
0117                 return f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
0118             });
0119         }
0120     };
0121     template <size_t... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
0122     struct FunctorCall<std::index_sequence<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...)> : FunctorCallBase
0123     {
0124         static void call(SlotRet (Obj::*f)(SlotArgs...), Obj *o, void **arg)
0125         {
0126             assertObjectType<Obj>(o);
0127             call_internal<R>(arg, [&] {
0128                 return (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
0129             });
0130         }
0131     };
0132     template <size_t... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
0133     struct FunctorCall<std::index_sequence<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) const> : FunctorCallBase
0134     {
0135         static void call(SlotRet (Obj::*f)(SlotArgs...) const, Obj *o, void **arg)
0136         {
0137             assertObjectType<Obj>(o);
0138             call_internal<R>(arg, [&] {
0139                 return (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
0140             });
0141         }
0142     };
0143     template <size_t... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
0144     struct FunctorCall<std::index_sequence<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) noexcept> : FunctorCallBase
0145     {
0146         static void call(SlotRet (Obj::*f)(SlotArgs...) noexcept, Obj *o, void **arg)
0147         {
0148             assertObjectType<Obj>(o);
0149             call_internal<R>(arg, [&]() noexcept {
0150                 return (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
0151             });
0152         }
0153     };
0154     template <size_t... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
0155     struct FunctorCall<std::index_sequence<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) const noexcept> : FunctorCallBase
0156     {
0157         static void call(SlotRet (Obj::*f)(SlotArgs...) const noexcept, Obj *o, void **arg)
0158         {
0159             assertObjectType<Obj>(o);
0160             call_internal<R>(arg, [&]() noexcept {
0161                 return (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
0162             });
0163         }
0164     };
0165 
0166     template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...)>
0167     {
0168         typedef Obj Object;
0169         typedef List<Args...>  Arguments;
0170         typedef Ret ReturnType;
0171         typedef Ret (Obj::*Function) (Args...);
0172         enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
0173         template <typename SignalArgs, typename R>
0174         static void call(Function f, Obj *o, void **arg) {
0175             FunctorCall<std::index_sequence_for<Args...>, SignalArgs, R, Function>::call(f, o, arg);
0176         }
0177     };
0178     template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...) const>
0179     {
0180         typedef Obj Object;
0181         typedef List<Args...>  Arguments;
0182         typedef Ret ReturnType;
0183         typedef Ret (Obj::*Function) (Args...) const;
0184         enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
0185         template <typename SignalArgs, typename R>
0186         static void call(Function f, Obj *o, void **arg) {
0187             FunctorCall<std::index_sequence_for<Args...>, SignalArgs, R, Function>::call(f, o, arg);
0188         }
0189     };
0190 
0191     template<typename Ret, typename... Args> struct FunctionPointer<Ret (*) (Args...)>
0192     {
0193         typedef List<Args...> Arguments;
0194         typedef Ret ReturnType;
0195         typedef Ret (*Function) (Args...);
0196         enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = false};
0197         template <typename SignalArgs, typename R>
0198         static void call(Function f, void *, void **arg) {
0199             FunctorCall<std::index_sequence_for<Args...>, SignalArgs, R, Function>::call(f, arg);
0200         }
0201     };
0202 
0203     template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...) noexcept>
0204     {
0205         typedef Obj Object;
0206         typedef List<Args...>  Arguments;
0207         typedef Ret ReturnType;
0208         typedef Ret (Obj::*Function) (Args...) noexcept;
0209         enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
0210         template <typename SignalArgs, typename R>
0211         static void call(Function f, Obj *o, void **arg) {
0212             FunctorCall<std::index_sequence_for<Args...>, SignalArgs, R, Function>::call(f, o, arg);
0213         }
0214     };
0215     template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...) const noexcept>
0216     {
0217         typedef Obj Object;
0218         typedef List<Args...>  Arguments;
0219         typedef Ret ReturnType;
0220         typedef Ret (Obj::*Function) (Args...) const noexcept;
0221         enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
0222         template <typename SignalArgs, typename R>
0223         static void call(Function f, Obj *o, void **arg) {
0224             FunctorCall<std::index_sequence_for<Args...>, SignalArgs, R, Function>::call(f, o, arg);
0225         }
0226     };
0227 
0228     template<typename Ret, typename... Args> struct FunctionPointer<Ret (*) (Args...) noexcept>
0229     {
0230         typedef List<Args...> Arguments;
0231         typedef Ret ReturnType;
0232         typedef Ret (*Function) (Args...) noexcept;
0233         enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = false};
0234         template <typename SignalArgs, typename R>
0235         static void call(Function f, void *, void **arg) {
0236             FunctorCall<std::index_sequence_for<Args...>, SignalArgs, R, Function>::call(f, arg);
0237         }
0238     };
0239 
0240     // Traits to detect if there is a conversion between two types,
0241     // and that conversion does not include a narrowing conversion.
0242     template <typename T>
0243     struct NarrowingDetector { T t[1]; }; // from P0608
0244 
0245     template <typename From, typename To, typename Enable = void>
0246     struct IsConvertibleWithoutNarrowing : std::false_type {};
0247 
0248     template <typename From, typename To>
0249     struct IsConvertibleWithoutNarrowing<From, To,
0250             std::void_t< decltype( NarrowingDetector<To>{ {std::declval<From>()} } ) >
0251         > : std::true_type {};
0252 
0253     // Check for the actual arguments. If they are exactly the same,
0254     // then don't bother checking for narrowing; as a by-product,
0255     // this solves the problem of incomplete types (which must be supported,
0256     // or they would error out in the trait above).
0257     template <typename From, typename To, typename Enable = void>
0258     struct AreArgumentsConvertibleWithoutNarrowingBase : std::false_type {};
0259 
0260     template <typename From, typename To>
0261     struct AreArgumentsConvertibleWithoutNarrowingBase<From, To,
0262         std::enable_if_t<
0263             std::disjunction_v<std::is_same<From, To>, IsConvertibleWithoutNarrowing<From, To>>
0264         >
0265     > : std::true_type {};
0266 
0267     /*
0268        Logic that check if the arguments of the slot matches the argument of the signal.
0269        To be used like this:
0270        static_assert(CheckCompatibleArguments<FunctionPointer<Signal>::Arguments, FunctionPointer<Slot>::Arguments>::value)
0271     */
0272     template<typename A1, typename A2> struct AreArgumentsCompatible {
0273         static int test(const std::remove_reference_t<A2>&);
0274         static char test(...);
0275         enum { value = sizeof(test(std::declval<std::remove_reference_t<A1>>())) == sizeof(int) };
0276 #ifdef QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
0277         using AreArgumentsConvertibleWithoutNarrowing = AreArgumentsConvertibleWithoutNarrowingBase<std::decay_t<A1>, std::decay_t<A2>>;
0278         static_assert(AreArgumentsConvertibleWithoutNarrowing::value, "Signal and slot arguments are not compatible (narrowing)");
0279 #endif
0280     };
0281     template<typename A1, typename A2> struct AreArgumentsCompatible<A1, A2&> { enum { value = false }; };
0282     template<typename A> struct AreArgumentsCompatible<A&, A&> { enum { value = true }; };
0283     // void as a return value
0284     template<typename A> struct AreArgumentsCompatible<void, A> { enum { value = true }; };
0285     template<typename A> struct AreArgumentsCompatible<A, void> { enum { value = true }; };
0286     template<> struct AreArgumentsCompatible<void, void> { enum { value = true }; };
0287 
0288     template <typename List1, typename List2> struct CheckCompatibleArguments { enum { value = false }; };
0289     template <> struct CheckCompatibleArguments<List<>, List<>> { enum { value = true }; };
0290     template <typename List1> struct CheckCompatibleArguments<List1, List<>> { enum { value = true }; };
0291     template <typename Arg1, typename Arg2, typename... Tail1, typename... Tail2>
0292     struct CheckCompatibleArguments<List<Arg1, Tail1...>, List<Arg2, Tail2...>>
0293     {
0294         enum { value = AreArgumentsCompatible<typename RemoveConstRef<Arg1>::Type, typename RemoveConstRef<Arg2>::Type>::value
0295                     && CheckCompatibleArguments<List<Tail1...>, List<Tail2...>>::value };
0296     };
0297 
0298     /*
0299        Find the maximum number of arguments a functor object can take and be still compatible with
0300        the arguments from the signal.
0301        Value is the number of arguments, or -1 if nothing matches.
0302      */
0303     template <typename Functor, typename ArgList> struct ComputeFunctorArgumentCount;
0304 
0305     template <typename Functor, typename ArgList, bool Done> struct ComputeFunctorArgumentCountHelper
0306     { enum { Value = -1 }; };
0307     template <typename Functor, typename First, typename... ArgList>
0308     struct ComputeFunctorArgumentCountHelper<Functor, List<First, ArgList...>, false>
0309         : ComputeFunctorArgumentCount<Functor,
0310             typename List_Left<List<First, ArgList...>, sizeof...(ArgList)>::Value> {};
0311 
0312     template <typename Functor, typename... ArgList> struct ComputeFunctorArgumentCount<Functor, List<ArgList...>>
0313     {
0314         template <typename F> static auto test(F f) -> decltype(((f.operator()((std::declval<ArgList>())...)), int()));
0315         static char test(...);
0316         enum {
0317             Ok = sizeof(test(std::declval<Functor>())) == sizeof(int),
0318             Value = Ok ? int(sizeof...(ArgList)) : int(ComputeFunctorArgumentCountHelper<Functor, List<ArgList...>, Ok>::Value)
0319         };
0320     };
0321 
0322     /* get the return type of a functor, given the signal argument list  */
0323     template <typename Functor, typename ArgList> struct FunctorReturnType;
0324     template <typename Functor, typename... ArgList> struct FunctorReturnType<Functor, List<ArgList...>>
0325         : std::invoke_result<Functor, ArgList...>
0326     { };
0327 
0328     template<typename Func, typename... Args>
0329     struct FunctorCallable
0330     {
0331         using ReturnType = std::invoke_result_t<Func, Args...>;
0332         using Function = ReturnType(*)(Args...);
0333         enum {ArgumentCount = sizeof...(Args)};
0334         using Arguments = QtPrivate::List<Args...>;
0335 
0336         template <typename SignalArgs, typename R>
0337         static void call(Func &f, void *, void **arg) {
0338             FunctorCall<std::index_sequence_for<Args...>, SignalArgs, R, Func>::call(f, arg);
0339         }
0340     };
0341 
0342     template <typename Functor, typename... Args>
0343     struct HasCallOperatorAcceptingArgs
0344     {
0345     private:
0346         template <typename F, typename = void>
0347         struct Test : std::false_type
0348         {
0349         };
0350         // We explicitly use .operator() to not return true for pointers to free/static function
0351         template <typename F>
0352         struct Test<F, std::void_t<decltype(std::declval<F>().operator()(std::declval<Args>()...))>>
0353             : std::true_type
0354         {
0355         };
0356 
0357     public:
0358         using Type = Test<Functor>;
0359         static constexpr bool value = Type::value;
0360     };
0361 
0362     template <typename Functor, typename... Args>
0363     constexpr bool
0364             HasCallOperatorAcceptingArgs_v = HasCallOperatorAcceptingArgs<Functor, Args...>::value;
0365 
0366     template <typename Func, typename... Args>
0367     struct CallableHelper
0368     {
0369     private:
0370         // Could've been std::conditional_t, but that requires all branches to
0371         // be valid
0372         static auto Resolve(std::true_type CallOperator) -> FunctorCallable<Func, Args...>;
0373         static auto Resolve(std::false_type CallOperator) -> FunctionPointer<std::decay_t<Func>>;
0374 
0375     public:
0376         using Type = decltype(Resolve(typename HasCallOperatorAcceptingArgs<std::decay_t<Func>,
0377                 Args...>::Type{}));
0378     };
0379 
0380     template<typename Func, typename... Args>
0381     struct Callable : CallableHelper<Func, Args...>::Type
0382     {};
0383     template<typename Func, typename... Args>
0384     struct Callable<Func, List<Args...>> : CallableHelper<Func, Args...>::Type
0385     {};
0386 
0387     /*
0388         Wrapper around ComputeFunctorArgumentCount and CheckCompatibleArgument,
0389         depending on whether \a Functor is a PMF or not. Returns -1 if \a Func is
0390         not compatible with the \a ExpectedArguments, otherwise returns >= 0.
0391     */
0392     template<typename Prototype, typename Functor>
0393     inline constexpr std::enable_if_t<!std::disjunction_v<std::is_convertible<Prototype, const char *>,
0394                                                           std::is_same<std::decay_t<Prototype>, QMetaMethod>,
0395                                                           std::is_convertible<Functor, const char *>,
0396                                                           std::is_same<std::decay_t<Functor>, QMetaMethod>
0397                                                          >,
0398                                       int>
0399     countMatchingArguments()
0400     {
0401         using ExpectedArguments = typename QtPrivate::FunctionPointer<Prototype>::Arguments;
0402         using Actual = std::decay_t<Functor>;
0403 
0404         if constexpr (QtPrivate::FunctionPointer<Actual>::IsPointerToMemberFunction
0405                    || QtPrivate::FunctionPointer<Actual>::ArgumentCount >= 0) {
0406             // PMF or free function
0407             using ActualArguments = typename QtPrivate::FunctionPointer<Actual>::Arguments;
0408             if constexpr (QtPrivate::CheckCompatibleArguments<ExpectedArguments, ActualArguments>::value)
0409                 return QtPrivate::FunctionPointer<Actual>::ArgumentCount;
0410             else
0411                 return -1;
0412         } else {
0413             // lambda or functor
0414             return QtPrivate::ComputeFunctorArgumentCount<Actual, ExpectedArguments>::Value;
0415         }
0416     }
0417 
0418     // internal base class (interface) containing functions required to call a slot managed by a pointer to function.
0419     class QSlotObjectBase
0420     {
0421         // Don't use virtual functions here; we don't want the
0422         // compiler to create tons of per-polymorphic-class stuff that
0423         // we'll never need. We just use one function pointer, and the
0424         // Operations enum below to distinguish requests
0425 #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
0426         QAtomicInt m_ref = 1;
0427         typedef void (*ImplFn)(int which, QSlotObjectBase* this_, QObject *receiver, void **args, bool *ret);
0428         const ImplFn m_impl;
0429 #else
0430         using ImplFn = void (*)(QSlotObjectBase* this_, QObject *receiver, void **args, int which, bool *ret);
0431         const ImplFn m_impl;
0432         QAtomicInt m_ref = 1;
0433 #endif
0434     protected:
0435         // The operations that can be requested by calls to m_impl,
0436         // see the member functions that call m_impl below for details
0437         enum Operation {
0438             Destroy,
0439             Call,
0440             Compare,
0441 
0442             NumOperations
0443         };
0444     public:
0445         explicit QSlotObjectBase(ImplFn fn) : m_impl(fn) {}
0446 
0447         // A custom deleter compatible with std protocols (op()()) we well as
0448         // the legacy QScopedPointer protocol (cleanup()).
0449         struct Deleter {
0450             void operator()(QSlotObjectBase *p) const noexcept
0451             { if (p) p->destroyIfLastRef(); }
0452             // for the non-standard QScopedPointer protocol:
0453             static void cleanup(QSlotObjectBase *p) noexcept { Deleter{}(p); }
0454         };
0455 
0456         bool ref() noexcept { return m_ref.ref(); }
0457 #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
0458         inline void destroyIfLastRef() noexcept
0459         { if (!m_ref.deref()) m_impl(Destroy, this, nullptr, nullptr, nullptr); }
0460 
0461         inline bool compare(void **a) { bool ret = false; m_impl(Compare, this, nullptr, a, &ret); return ret; }
0462         inline void call(QObject *r, void **a)  { m_impl(Call, this, r, a, nullptr); }
0463 #else
0464         inline void destroyIfLastRef() noexcept
0465         { if (!m_ref.deref()) m_impl(this, nullptr, nullptr, Destroy, nullptr); }
0466 
0467         inline bool compare(void **a)
0468         {
0469             bool ret = false;
0470             m_impl(this, nullptr, a, Compare, &ret);
0471             return ret;
0472         }
0473         inline void call(QObject *r, void **a)  { m_impl(this, r, a, Call, nullptr); }
0474 #endif
0475         bool isImpl(ImplFn f) const { return m_impl == f; }
0476     protected:
0477         ~QSlotObjectBase() {}
0478     private:
0479         Q_DISABLE_COPY_MOVE(QSlotObjectBase)
0480     };
0481 
0482     using SlotObjUniquePtr = std::unique_ptr<QSlotObjectBase,
0483                                              QSlotObjectBase::Deleter>;
0484     inline SlotObjUniquePtr copy(const SlotObjUniquePtr &other) noexcept
0485     {
0486         if (other)
0487             other->ref();
0488         return SlotObjUniquePtr{other.get()};
0489     }
0490 
0491     class SlotObjSharedPtr {
0492         SlotObjUniquePtr obj;
0493     public:
0494         Q_NODISCARD_CTOR Q_IMPLICIT SlotObjSharedPtr() noexcept = default;
0495         Q_NODISCARD_CTOR Q_IMPLICIT SlotObjSharedPtr(std::nullptr_t) noexcept : SlotObjSharedPtr() {}
0496         Q_NODISCARD_CTOR explicit SlotObjSharedPtr(SlotObjUniquePtr o)
0497             : obj(std::move(o))
0498         {
0499             // does NOT ref() (takes unique_ptr by value)
0500             // (that's why (QSlotObjectBase*) ctor doesn't exisit: don't know whether that one _should_)
0501         }
0502         Q_NODISCARD_CTOR SlotObjSharedPtr(const SlotObjSharedPtr &other) noexcept
0503             : obj{copy(other.obj)} {}
0504         SlotObjSharedPtr &operator=(const SlotObjSharedPtr &other) noexcept
0505         { auto copy = other; swap(copy); return *this; }
0506 
0507         Q_NODISCARD_CTOR SlotObjSharedPtr(SlotObjSharedPtr &&other) noexcept = default;
0508         SlotObjSharedPtr &operator=(SlotObjSharedPtr &&other) noexcept = default;
0509         ~SlotObjSharedPtr() = default;
0510 
0511         void swap(SlotObjSharedPtr &other) noexcept { obj.swap(other.obj); }
0512 
0513         auto get() const noexcept { return obj.get(); }
0514         auto operator->() const noexcept { return get(); }
0515 
0516         explicit operator bool() const noexcept { return bool(obj); }
0517     };
0518 
0519 
0520     // Implementation of QSlotObjectBase for which the slot is a callable (function, PMF, functor, or lambda).
0521     // Args and R are the List of arguments and the return type of the signal to which the slot is connected.
0522     template <typename Func, typename Args, typename R>
0523     class QCallableObject : public QSlotObjectBase,
0524                             private QtPrivate::CompactStorage<std::decay_t<Func>>
0525     {
0526         using FunctorValue = std::decay_t<Func>;
0527         using Storage = QtPrivate::CompactStorage<FunctorValue>;
0528         using FuncType = Callable<Func, Args>;
0529 
0530 #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
0531         Q_DECL_HIDDEN static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
0532 #else
0533         // Design note: the first three arguments match those for typical Call
0534         // and Destroy uses. We return void to enable tail call optimization
0535         // for those too.
0536         Q_DECL_HIDDEN static void impl(QSlotObjectBase *this_, QObject *r, void **a, int which, bool *ret)
0537 #endif
0538         {
0539             const auto that = static_cast<QCallableObject*>(this_);
0540             switch (which) {
0541             case Destroy:
0542                 delete that;
0543                 break;
0544             case Call:
0545                 if constexpr (std::is_member_function_pointer_v<FunctorValue>)
0546                     FuncType::template call<Args, R>(that->object(), static_cast<typename FuncType::Object *>(r), a);
0547                 else
0548                     FuncType::template call<Args, R>(that->object(), r, a);
0549                 break;
0550             case Compare:
0551                 if constexpr (std::is_member_function_pointer_v<FunctorValue>) {
0552                     *ret = *reinterpret_cast<FunctorValue *>(a) == that->object();
0553                     break;
0554                 }
0555                 // not implemented otherwise
0556                 Q_FALLTHROUGH();
0557             case NumOperations:
0558                 Q_UNUSED(ret);
0559             }
0560         }
0561     public:
0562         explicit QCallableObject(Func &&f) : QSlotObjectBase(&impl), Storage{std::move(f)} {}
0563         explicit QCallableObject(const Func &f) : QSlotObjectBase(&impl), Storage{f} {}
0564     };
0565 
0566     // Helper to detect the context object type based on the functor type:
0567     // QObject for free functions and lambdas; the callee for member function
0568     // pointers. The default declaration doesn't have the ContextType typedef,
0569     // and so non-functor APIs (like old-style string-based slots) are removed
0570     // from the overload set.
0571     template <typename Func, typename = void>
0572     struct ContextTypeForFunctor {};
0573 
0574     template <typename Func>
0575     struct ContextTypeForFunctor<Func,
0576         std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
0577                                              std::is_member_function_pointer<Func>
0578                                             >
0579                         >
0580     >
0581     {
0582         using ContextType = QObject;
0583     };
0584     template <typename Func>
0585     struct ContextTypeForFunctor<Func,
0586         std::enable_if_t<std::conjunction_v<std::negation<std::is_convertible<Func, const char *>>,
0587                                             std::is_member_function_pointer<Func>,
0588                                             std::is_convertible<typename QtPrivate::FunctionPointer<Func>::Object *, QObject *>
0589                                            >
0590                         >
0591     >
0592     {
0593         using ContextType = typename QtPrivate::FunctionPointer<Func>::Object;
0594     };
0595 
0596     /*
0597         Returns a suitable QSlotObjectBase object that holds \a func, if possible.
0598 
0599         Not available (and thus produces compile-time errors) if the Functor provided is
0600         not compatible with the expected Prototype.
0601     */
0602     template <typename Prototype, typename Functor>
0603     static constexpr std::enable_if_t<QtPrivate::countMatchingArguments<Prototype, Functor>() >= 0,
0604         QtPrivate::QSlotObjectBase *>
0605     makeCallableObject(Functor &&func)
0606     {
0607         using ExpectedSignature = QtPrivate::FunctionPointer<Prototype>;
0608         using ExpectedReturnType = typename ExpectedSignature::ReturnType;
0609         using ExpectedArguments = typename ExpectedSignature::Arguments;
0610 
0611         using ActualSignature = QtPrivate::FunctionPointer<Functor>;
0612         constexpr int MatchingArgumentCount = QtPrivate::countMatchingArguments<Prototype, Functor>();
0613         using ActualArguments  = typename QtPrivate::List_Left<ExpectedArguments, MatchingArgumentCount>::Value;
0614 
0615         static_assert(int(ActualSignature::ArgumentCount) <= int(ExpectedSignature::ArgumentCount),
0616             "Functor requires more arguments than what can be provided.");
0617 
0618         // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
0619         return new QtPrivate::QCallableObject<std::decay_t<Functor>, ActualArguments, ExpectedReturnType>(std::forward<Functor>(func));
0620     }
0621 
0622     template<typename Prototype, typename Functor, typename = void>
0623     struct AreFunctionsCompatible : std::false_type {};
0624     template<typename Prototype, typename Functor>
0625     struct AreFunctionsCompatible<Prototype, Functor, std::enable_if_t<
0626         std::is_same_v<decltype(QtPrivate::makeCallableObject<Prototype>(std::forward<Functor>(std::declval<Functor>()))),
0627         QtPrivate::QSlotObjectBase *>>
0628     > : std::true_type {};
0629 
0630     template<typename Prototype, typename Functor>
0631     inline constexpr bool AssertCompatibleFunctions() {
0632         static_assert(AreFunctionsCompatible<Prototype, Functor>::value,
0633                       "Functor is not compatible with expected prototype!");
0634         return true;
0635     }
0636 } // namespace QtPrivate
0637 
0638 QT_END_NAMESPACE
0639