Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 09:26:41

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