Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/QtCore/qobjectdefs_impl.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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