Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qobjectdefs_impl.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QOBJECTDEFS_H
6#error Do not include qobjectdefs_impl.h directly
7#include <QtCore/qnamespace.h>
8#endif
9
10#if 0
11#pragma qt_sync_skip_header_check
12#pragma qt_sync_stop_processing
13#endif
14
15#include <QtCore/qfunctionaltools_impl.h>
16
17#include <memory>
18
20class QObject;
21class QObjectPrivate;
22class QMetaMethod;
23class QByteArray;
24
25namespace QtPrivate {
26 template <typename T> struct RemoveRef { typedef T Type; };
27 template <typename T> struct RemoveRef<T&> { typedef T Type; };
28 template <typename T> struct RemoveConstRef { typedef T Type; };
29 template <typename T> struct RemoveConstRef<const T&> { typedef T Type; };
30
31 /*
32 The following List classes are used to help to handle the list of arguments.
33 It follow the same principles as the lisp lists.
34 List_Left<L,N> take a list and a number as a parameter and returns (via the Value typedef,
35 the list composed of the first N element of the list
36 */
37 // With variadic template, lists are represented using a variadic template argument instead of the lisp way
38 template <typename... Ts> struct List { static constexpr size_t size = sizeof...(Ts); };
39 template<typename T> struct SizeOfList { static constexpr size_t value = 1; };
40 template<> struct SizeOfList<List<>> { static constexpr size_t value = 0; };
41 template<typename ...Ts> struct SizeOfList<List<Ts...>> { static constexpr size_t value = List<Ts...>::size; };
42 template <typename Head, typename... Tail> struct List<Head, Tail...> {
43 static constexpr size_t size = 1 + sizeof...(Tail);
44 typedef Head Car; typedef List<Tail...> Cdr;
45 };
46 template <typename, typename> struct List_Append;
47 template <typename... L1, typename...L2> struct List_Append<List<L1...>, List<L2...>> { typedef List<L1..., L2...> Value; };
48 template <typename L, int N> struct List_Left {
49 typedef typename List_Append<List<typename L::Car>,typename List_Left<typename L::Cdr, N - 1>::Value>::Value Value;
50 };
51 template <typename L> struct List_Left<L, 0> { typedef List<> Value; };
52
53 /*
54 This is used to store the return value from a slot, whether the caller
55 wants to store this value (QMetaObject::invokeMethod() with
56 qReturnArg() or non-void signal ) or not.
57 */
59 {
60 template <typename R, typename Lambda>
61 static void call_internal(void **args, Lambda &&fn) noexcept(noexcept(fn()))
62 {
63 using SlotRet = decltype(fn());
64 if constexpr (std::is_void_v<R> || std::is_void_v<SlotRet>) {
66 } else {
67 if (args[0]) {
68 *reinterpret_cast<R *>(args[0]) = fn();
69 return;
70 }
71 }
72 fn();
73 }
74 };
75
76 /*
77 The FunctionPointer<Func> struct is a type trait for function pointer.
78 - ArgumentCount is the number of argument, or -1 if it is unknown
79 - the Object typedef is the Object of a pointer to member function
80 - the Arguments typedef is the list of argument (in a QtPrivate::List)
81 - the Function typedef is an alias to the template parameter Func
82 - the call<Args, R>(f,o,args) method is used to call that slot
83 Args is the list of argument of the signal
84 R is the return type of the signal
85 f is the function pointer
86 o is the receiver object
87 and args is the array of pointer to arguments, as used in qt_metacall
88
89 The Functor<Func,N> struct is the helper to call a functor of N argument.
90 Its call function is the same as the FunctionPointer::call function.
91 */
92 template<class T> using InvokeGenSeq = typename T::Type;
93
94 template<int...> struct IndexesList { using Type = IndexesList; };
95
96 template<int N, class S1, class S2> struct ConcatSeqImpl;
97
98 template<int N, int... I1, int... I2>
99 struct ConcatSeqImpl<N, IndexesList<I1...>, IndexesList<I2...>>
100 : IndexesList<I1..., (N + I2)...>{};
101
102 template<int N, class S1, class S2>
103 using ConcatSeq = InvokeGenSeq<ConcatSeqImpl<N, S1, S2>>;
104
105 template<int N> struct GenSeq;
106 template<int N> using makeIndexSequence = InvokeGenSeq<GenSeq<N>>;
107
108 template<int N>
109 struct GenSeq : ConcatSeq<N/2, makeIndexSequence<N/2>, makeIndexSequence<N - N/2>>{};
110
111 template<> struct GenSeq<0> : IndexesList<>{};
112 template<> struct GenSeq<1> : IndexesList<0>{};
113
114 template<int N>
115 struct Indexes { using Value = makeIndexSequence<N>; };
116
117 template<typename Func> struct FunctionPointer { enum {ArgumentCount = -1, IsPointerToMemberFunction = false}; };
118
119 template<typename ObjPrivate> inline void assertObjectType(QObjectPrivate *d);
120 template<typename Obj> inline void assertObjectType(QObject *o)
121 {
122 // ensure all three compile
123 [[maybe_unused]] auto staticcast = [](QObject *obj) { return static_cast<Obj *>(obj); };
124 [[maybe_unused]] auto qobjcast = [](QObject *obj) { return Obj::staticMetaObject.cast(obj); };
125#ifdef __cpp_rtti
126 [[maybe_unused]] auto dyncast = [](QObject *obj) { return dynamic_cast<Obj *>(obj); };
127 auto cast = dyncast;
128#else
129 auto cast = qobjcast;
130#endif
131 Q_ASSERT_X(cast(o), Obj::staticMetaObject.className(),
132 "Called object is not of the correct type (class destructor may have already run)");
133 }
134
135 template <typename, typename, typename, typename> struct FunctorCall;
136 template <int... II, typename... SignalArgs, typename R, typename Function>
137 struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, Function> : FunctorCallBase
138 {
139 static void call(Function &f, void **arg)
140 {
141 call_internal<R>(arg, [&] {
142 return f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
143 });
144 }
145 };
146 template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
147 struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...)> : FunctorCallBase
148 {
149 static void call(SlotRet (Obj::*f)(SlotArgs...), Obj *o, void **arg)
150 {
151 assertObjectType<Obj>(o);
152 call_internal<R>(arg, [&] {
153 return (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
154 });
155 }
156 };
157 template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
158 struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) const> : FunctorCallBase
159 {
160 static void call(SlotRet (Obj::*f)(SlotArgs...) const, Obj *o, void **arg)
161 {
162 assertObjectType<Obj>(o);
163 call_internal<R>(arg, [&] {
164 return (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
165 });
166 }
167 };
168 template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
169 struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) noexcept> : FunctorCallBase
170 {
171 static void call(SlotRet (Obj::*f)(SlotArgs...) noexcept, Obj *o, void **arg)
172 {
173 assertObjectType<Obj>(o);
174 call_internal<R>(arg, [&]() noexcept {
175 return (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
176 });
177 }
178 };
179 template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
180 struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) const noexcept> : FunctorCallBase
181 {
182 static void call(SlotRet (Obj::*f)(SlotArgs...) const noexcept, Obj *o, void **arg)
183 {
184 assertObjectType<Obj>(o);
185 call_internal<R>(arg, [&]() noexcept {
186 return (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
187 });
188 }
189 };
190
191 template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...)>
192 {
193 typedef Obj Object;
194 typedef List<Args...> Arguments;
195 typedef Ret ReturnType;
196 typedef Ret (Obj::*Function) (Args...);
197 enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
198 template <typename SignalArgs, typename R>
199 static void call(Function f, Obj *o, void **arg) {
200 FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
201 }
202 };
203 template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...) const>
204 {
205 typedef Obj Object;
206 typedef List<Args...> Arguments;
207 typedef Ret ReturnType;
208 typedef Ret (Obj::*Function) (Args...) const;
209 enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
210 template <typename SignalArgs, typename R>
211 static void call(Function f, Obj *o, void **arg) {
212 FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
213 }
214 };
215
216 template<typename Ret, typename... Args> struct FunctionPointer<Ret (*) (Args...)>
217 {
218 typedef List<Args...> Arguments;
219 typedef Ret ReturnType;
220 typedef Ret (*Function) (Args...);
221 enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = false};
222 template <typename SignalArgs, typename R>
223 static void call(Function f, void *, void **arg) {
224 FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, arg);
225 }
226 };
227
228 template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...) noexcept>
229 {
230 typedef Obj Object;
231 typedef List<Args...> Arguments;
232 typedef Ret ReturnType;
233 typedef Ret (Obj::*Function) (Args...) noexcept;
234 enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
235 template <typename SignalArgs, typename R>
236 static void call(Function f, Obj *o, void **arg) {
237 FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
238 }
239 };
240 template<class Obj, typename Ret, typename... Args> struct FunctionPointer<Ret (Obj::*) (Args...) const noexcept>
241 {
242 typedef Obj Object;
243 typedef List<Args...> Arguments;
244 typedef Ret ReturnType;
245 typedef Ret (Obj::*Function) (Args...) const noexcept;
246 enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
247 template <typename SignalArgs, typename R>
248 static void call(Function f, Obj *o, void **arg) {
249 FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
250 }
251 };
252
253 template<typename Ret, typename... Args> struct FunctionPointer<Ret (*) (Args...) noexcept>
254 {
255 typedef List<Args...> Arguments;
256 typedef Ret ReturnType;
257 typedef Ret (*Function) (Args...) noexcept;
258 enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = false};
259 template <typename SignalArgs, typename R>
260 static void call(Function f, void *, void **arg) {
261 FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, arg);
262 }
263 };
264
265 // Traits to detect if there is a conversion between two types,
266 // and that conversion does not include a narrowing conversion.
267 template <typename T>
268 struct NarrowingDetector { T t[1]; }; // from P0608
269
270 template <typename From, typename To, typename Enable = void>
271 struct IsConvertibleWithoutNarrowing : std::false_type {};
272
273 template <typename From, typename To>
275 std::void_t< decltype( NarrowingDetector<To>{ {std::declval<From>()} } ) >
276 > : std::true_type {};
277
278 // Check for the actual arguments. If they are exactly the same,
279 // then don't bother checking for narrowing; as a by-product,
280 // this solves the problem of incomplete types (which must be supported,
281 // or they would error out in the trait above).
282 template <typename From, typename To, typename Enable = void>
284
285 template <typename From, typename To>
287 std::enable_if_t<
288 std::disjunction_v<std::is_same<From, To>, IsConvertibleWithoutNarrowing<From, To>>
289 >
290 > : std::true_type {};
291
292 /*
293 Logic that check if the arguments of the slot matches the argument of the signal.
294 To be used like this:
295 static_assert(CheckCompatibleArguments<FunctionPointer<Signal>::Arguments, FunctionPointer<Slot>::Arguments>::value)
296 */
297 template<typename A1, typename A2> struct AreArgumentsCompatible {
298 static int test(const std::remove_reference_t<A2>&);
299 static char test(...);
300 enum { value = sizeof(test(std::declval<std::remove_reference_t<A1>>())) == sizeof(int) };
301#ifdef QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
302 using AreArgumentsConvertibleWithoutNarrowing = AreArgumentsConvertibleWithoutNarrowingBase<std::decay_t<A1>, std::decay_t<A2>>;
303 static_assert(AreArgumentsConvertibleWithoutNarrowing::value, "Signal and slot arguments are not compatible (narrowing)");
304#endif
305 };
306 template<typename A1, typename A2> struct AreArgumentsCompatible<A1, A2&> { enum { value = false }; };
307 template<typename A> struct AreArgumentsCompatible<A&, A&> { enum { value = true }; };
308 // void as a return value
309 template<typename A> struct AreArgumentsCompatible<void, A> { enum { value = true }; };
310 template<typename A> struct AreArgumentsCompatible<A, void> { enum { value = true }; };
311 template<> struct AreArgumentsCompatible<void, void> { enum { value = true }; };
312
313 template <typename List1, typename List2> struct CheckCompatibleArguments { enum { value = false }; };
314 template <> struct CheckCompatibleArguments<List<>, List<>> { enum { value = true }; };
315 template <typename List1> struct CheckCompatibleArguments<List1, List<>> { enum { value = true }; };
316 template <typename Arg1, typename Arg2, typename... Tail1, typename... Tail2>
317 struct CheckCompatibleArguments<List<Arg1, Tail1...>, List<Arg2, Tail2...>>
318 {
319 enum { value = AreArgumentsCompatible<typename RemoveConstRef<Arg1>::Type, typename RemoveConstRef<Arg2>::Type>::value
320 && CheckCompatibleArguments<List<Tail1...>, List<Tail2...>>::value };
321 };
322
323 /*
324 Find the maximum number of arguments a functor object can take and be still compatible with
325 the arguments from the signal.
326 Value is the number of arguments, or -1 if nothing matches.
327 */
328 template <typename Functor, typename ArgList> struct ComputeFunctorArgumentCount;
329
330 template <typename Functor, typename ArgList, bool Done> struct ComputeFunctorArgumentCountHelper
331 { enum { Value = -1 }; };
332 template <typename Functor, typename First, typename... ArgList>
335 typename List_Left<List<First, ArgList...>, sizeof...(ArgList)>::Value> {};
336
337 template <typename Functor, typename... ArgList> struct ComputeFunctorArgumentCount<Functor, List<ArgList...>>
338 {
339 template <typename F> static auto test(F f) -> decltype(((f.operator()((std::declval<ArgList>())...)), int()));
340 static char test(...);
341 enum {
342 Ok = sizeof(test(std::declval<Functor>())) == sizeof(int),
343 Value = Ok ? int(sizeof...(ArgList)) : int(ComputeFunctorArgumentCountHelper<Functor, List<ArgList...>, Ok>::Value)
344 };
345 };
346
347 /* get the return type of a functor, given the signal argument list */
348 template <typename Functor, typename ArgList> struct FunctorReturnType;
349 template <typename Functor, typename ... ArgList> struct FunctorReturnType<Functor, List<ArgList...>> {
350 typedef decltype(std::declval<Functor>().operator()((std::declval<ArgList>())...)) Value;
351 };
352
353 template<typename Func, typename... Args>
355 {
356 using ReturnType = decltype(std::declval<Func>()(std::declval<Args>()...));
357 using Function = ReturnType(*)(Args...);
358 enum {ArgumentCount = sizeof...(Args)};
359 using Arguments = QtPrivate::List<Args...>;
360
361 template <typename SignalArgs, typename R>
362 static void call(Func &f, void *, void **arg) {
363 FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Func>::call(f, arg);
364 }
365 };
366
367 template <typename Functor, typename... Args>
369 {
370 private:
371 template <typename F, typename = void>
372 struct Test : std::false_type
373 {
374 };
375 // We explicitly use .operator() to not return true for pointers to free/static function
376 template <typename F>
377 struct Test<F, std::void_t<decltype(std::declval<F>().operator()(std::declval<Args>()...))>>
378 : std::true_type
379 {
380 };
381
382 public:
383 using Type = Test<Functor>;
384 static constexpr bool value = Type::value;
385 };
386
387 template <typename Functor, typename... Args>
388 constexpr bool
390
391 template <typename Func, typename... Args>
393 {
394 private:
395 // Could've been std::conditional_t, but that requires all branches to
396 // be valid
397 static auto Resolve(std::true_type CallOperator) -> FunctorCallable<Func, Args...>;
398 static auto Resolve(std::false_type CallOperator) -> FunctionPointer<std::decay_t<Func>>;
399
400 public:
401 using Type = decltype(Resolve(typename HasCallOperatorAcceptingArgs<std::decay_t<Func>,
402 Args...>::Type{}));
403 };
404
405 template<typename Func, typename... Args>
406 struct Callable : CallableHelper<Func, Args...>::Type
407 {};
408 template<typename Func, typename... Args>
409 struct Callable<Func, List<Args...>> : CallableHelper<Func, Args...>::Type
410 {};
411
412 /*
413 Wrapper around ComputeFunctorArgumentCount and CheckCompatibleArgument,
414 depending on whether \a Functor is a PMF or not. Returns -1 if \a Func is
415 not compatible with the \a ExpectedArguments, otherwise returns >= 0.
416 */
417 template<typename Prototype, typename Functor>
418 inline constexpr std::enable_if_t<!std::disjunction_v<std::is_convertible<Prototype, const char *>,
419 std::is_same<std::decay_t<Prototype>, QMetaMethod>,
420 std::is_convertible<Functor, const char *>,
421 std::is_same<std::decay_t<Functor>, QMetaMethod>
422 >,
423 int>
425 {
426 using ExpectedArguments = typename QtPrivate::FunctionPointer<Prototype>::Arguments;
427 using Actual = std::decay_t<Functor>;
428
431 // PMF or free function
432 using ActualArguments = typename QtPrivate::FunctionPointer<Actual>::Arguments;
435 else
436 return -1;
437 } else {
438 // lambda or functor
440 }
441 }
442
443 // internal base class (interface) containing functions required to call a slot managed by a pointer to function.
445 {
446 // Don't use virtual functions here; we don't want the
447 // compiler to create tons of per-polymorphic-class stuff that
448 // we'll never need. We just use one function pointer, and the
449 // Operations enum below to distinguish requests
450#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
451 QAtomicInt m_ref = 1;
452 typedef void (*ImplFn)(int which, QSlotObjectBase* this_, QObject *receiver, void **args, bool *ret);
453 const ImplFn m_impl;
454#else
455 using ImplFn = void (*)(QSlotObjectBase* this_, QObject *receiver, void **args, int which, bool *ret);
456 const ImplFn m_impl;
457 QAtomicInt m_ref = 1;
458#endif
459 protected:
460 // The operations that can be requested by calls to m_impl,
461 // see the member functions that call m_impl below for details
466
467 NumOperations
468 };
469 public:
470 explicit QSlotObjectBase(ImplFn fn) : m_impl(fn) {}
471
472 // A custom deleter compatible with std protocols (op()()) we well as
473 // the legacy QScopedPointer protocol (cleanup()).
474 struct Deleter {
475 void operator()(QSlotObjectBase *p) const noexcept
476 { if (p) p->destroyIfLastRef(); }
477 // for the non-standard QScopedPointer protocol:
478 static void cleanup(QSlotObjectBase *p) noexcept { Deleter{}(p); }
479 };
480
481 bool ref() noexcept { return m_ref.ref(); }
482#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
483 inline void destroyIfLastRef() noexcept
484 { if (!m_ref.deref()) m_impl(Destroy, this, nullptr, nullptr, nullptr); }
485
486 inline bool compare(void **a) { bool ret = false; m_impl(Compare, this, nullptr, a, &ret); return ret; }
487 inline void call(QObject *r, void **a) { m_impl(Call, this, r, a, nullptr); }
488#else
489 inline void destroyIfLastRef() noexcept
490 { if (!m_ref.deref()) m_impl(this, nullptr, nullptr, Destroy, nullptr); }
491
492 inline bool compare(void **a)
493 {
494 bool ret = false;
495 m_impl(this, nullptr, a, Compare, &ret);
496 return ret;
497 }
498 inline void call(QObject *r, void **a) { m_impl(this, r, a, Call, nullptr); }
499#endif
500 bool isImpl(ImplFn f) const { return m_impl == f; }
501 protected:
503 private:
504 Q_DISABLE_COPY_MOVE(QSlotObjectBase)
505 };
506
507 using SlotObjUniquePtr = std::unique_ptr<QSlotObjectBase,
510 {
511 if (other)
512 other->ref();
513 return SlotObjUniquePtr{other.get()};
514 }
515
518 public:
522 : obj(std::move(o))
523 {
524 // does NOT ref() (takes unique_ptr by value)
525 // (that's why (QSlotObjectBase*) ctor doesn't exisit: don't know whether that one _should_)
526 }
530 { auto copy = other; swap(copy); return *this; }
531
534 ~SlotObjSharedPtr() = default;
535
536 void swap(SlotObjSharedPtr &other) noexcept { obj.swap(other.obj); }
537
538 auto get() const noexcept { return obj.get(); }
539 auto operator->() const noexcept { return get(); }
540
541 explicit operator bool() const noexcept { return bool(obj); }
542 };
543
544
545 // Implementation of QSlotObjectBase for which the slot is a callable (function, PMF, functor, or lambda).
546 // Args and R are the List of arguments and the return type of the signal to which the slot is connected.
547 template <typename Func, typename Args, typename R>
549 private QtPrivate::CompactStorage<std::decay_t<Func>>
550 {
551 using FunctorValue = std::decay_t<Func>;
553 using FuncType = Callable<Func, Args>;
554
555#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
556 Q_DECL_HIDDEN static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
557#else
558 // Design note: the first three arguments match those for typical Call
559 // and Destroy uses. We return void to enable tail call optimization
560 // for those too.
561 Q_DECL_HIDDEN static void impl(QSlotObjectBase *this_, QObject *r, void **a, int which, bool *ret)
562#endif
563 {
564 const auto that = static_cast<QCallableObject*>(this_);
565 switch (which) {
566 case Destroy:
567 delete that;
568 break;
569 case Call:
570 if constexpr (std::is_member_function_pointer_v<FunctorValue>)
571 FuncType::template call<Args, R>(that->object(), static_cast<typename FuncType::Object *>(r), a);
572 else
573 FuncType::template call<Args, R>(that->object(), r, a);
574 break;
575 case Compare:
576 if constexpr (std::is_member_function_pointer_v<FunctorValue>) {
577 *ret = *reinterpret_cast<FunctorValue *>(a) == that->object();
578 break;
579 }
580 // not implemented otherwise
582 case NumOperations:
583 Q_UNUSED(ret);
584 }
585 }
586 public:
587 explicit QCallableObject(Func &&f) : QSlotObjectBase(&impl), Storage{std::move(f)} {}
588 explicit QCallableObject(const Func &f) : QSlotObjectBase(&impl), Storage{f} {}
589 };
590
591 // Helper to detect the context object type based on the functor type:
592 // QObject for free functions and lambdas; the callee for member function
593 // pointers. The default declaration doesn't have the ContextType typedef,
594 // and so non-functor APIs (like old-style string-based slots) are removed
595 // from the overload set.
596 template <typename Func, typename = void>
598
599 template <typename Func>
601 std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
602 std::is_member_function_pointer<Func>
603 >
604 >
605 >
606 {
608 };
609 template <typename Func>
611 std::enable_if_t<std::conjunction_v<std::negation<std::is_convertible<Func, const char *>>,
612 std::is_member_function_pointer<Func>,
613 std::is_convertible<typename QtPrivate::FunctionPointer<Func>::Object *, QObject *>
614 >
615 >
616 >
617 {
619 };
620
621 /*
622 Returns a suitable QSlotObjectBase object that holds \a func, if possible.
623
624 Not available (and thus produces compile-time errors) if the Functor provided is
625 not compatible with the expected Prototype.
626 */
627 template <typename Prototype, typename Functor>
628 static constexpr std::enable_if_t<QtPrivate::countMatchingArguments<Prototype, Functor>() >= 0,
631 {
632 using ExpectedSignature = QtPrivate::FunctionPointer<Prototype>;
633 using ExpectedReturnType = typename ExpectedSignature::ReturnType;
634 using ExpectedArguments = typename ExpectedSignature::Arguments;
635
636 using ActualSignature = QtPrivate::FunctionPointer<Functor>;
637 constexpr int MatchingArgumentCount = QtPrivate::countMatchingArguments<Prototype, Functor>();
639
640 static_assert(int(ActualSignature::ArgumentCount) <= int(ExpectedSignature::ArgumentCount),
641 "Functor requires more arguments than what can be provided.");
642
643 // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
644 return new QtPrivate::QCallableObject<std::decay_t<Functor>, ActualArguments, ExpectedReturnType>(std::forward<Functor>(func));
645 }
646
647 template<typename Prototype, typename Functor, typename = void>
648 struct AreFunctionsCompatible : std::false_type {};
649 template<typename Prototype, typename Functor>
650 struct AreFunctionsCompatible<Prototype, Functor, std::enable_if_t<
651 std::is_same_v<decltype(QtPrivate::makeCallableObject<Prototype>(std::forward<Functor>(std::declval<Functor>()))),
652 QtPrivate::QSlotObjectBase *>>
653 > : std::true_type {};
654
655 template<typename Prototype, typename Functor>
656 inline constexpr bool AssertCompatibleFunctions() {
658 "Functor is not compatible with expected prototype!");
659 return true;
660 }
661}
662
664
\inmodule QtCore
Definition qatomic.h:112
bool ref() noexcept
bool deref() noexcept
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qmetaobject.h:19
\inmodule QtCore
Definition qobject.h:103
bool isImpl(ImplFn f) const
void call(QObject *r, void **a)
SlotObjSharedPtr & operator=(SlotObjSharedPtr &&other) noexcept=default
Q_NODISCARD_CTOR SlotObjSharedPtr(SlotObjUniquePtr o)
auto operator->() const noexcept
void swap(SlotObjSharedPtr &other) noexcept
Q_NODISCARD_CTOR Q_IMPLICIT SlotObjSharedPtr() noexcept=default
auto get() const noexcept
Q_NODISCARD_CTOR SlotObjSharedPtr(SlotObjSharedPtr &&other) noexcept=default
Q_NODISCARD_CTOR SlotObjSharedPtr(const SlotObjSharedPtr &other) noexcept
SlotObjSharedPtr & operator=(const SlotObjSharedPtr &other) noexcept
Combined button and popup list for selecting options.
\macro QT_NO_KEYWORDS >
typename std::conditional_t< std::conjunction_v< std::is_empty< Object >, std::negation< std::is_final< Object > > >, detail::StorageEmptyBaseClassOptimization< Object, Tag >, detail::StorageByValue< Object, Tag > > CompactStorage
void assertObjectType(QObjectPrivate *d)
Definition qobject_p.h:262
constexpr bool HasCallOperatorAcceptingArgs_v
typename T::Type InvokeGenSeq
constexpr std::enable_if_t<!std::disjunction_v< std::is_convertible< Prototype, const char * >, std::is_same< std::decay_t< Prototype >, QMetaMethod >, std::is_convertible< Functor, const char * >, std::is_same< std::decay_t< Functor >, QMetaMethod > >, int > countMatchingArguments()
constexpr bool AssertCompatibleFunctions()
std::unique_ptr< QSlotObjectBase, QSlotObjectBase::Deleter > SlotObjUniquePtr
InvokeGenSeq< GenSeq< N > > makeIndexSequence
InvokeGenSeq< ConcatSeqImpl< N, S1, S2 > > ConcatSeq
SlotObjUniquePtr copy(const SlotObjUniquePtr &other) noexcept
static constexpr std::enable_if_t< QtPrivate::countMatchingArguments< Prototype, Functor >() >=0, QtPrivate::QSlotObjectBase * > makeCallableObject(Functor &&func)
static jboolean copy(JNIEnv *, jobject)
@ Ok
Definition qbezier.cpp:173
#define Q_NODISCARD_CTOR
#define Q_FALLTHROUGH()
#define Q_DECL_HIDDEN
#define Q_IMPLICIT
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
static QDBusError::ErrorType get(const char *name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
return ret
n varying highp vec2 A
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLfloat GLfloat f
GLhandleARB obj
[2]
GLenum func
Definition qopenglext.h:663
GLdouble GLdouble t
Definition qopenglext.h:243
GLfloat GLfloat p
[1]
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
SSL_CTX int void * arg
#define Q_UNUSED(x)
static int compare(quint64 a, quint64 b)
const char className[16]
[1]
Definition qwizard.cpp:100
QSharedPointer< T > other(t)
[5]
this swap(other)
QJSValueList args
static int test(const std::remove_reference_t< A2 > &)
static auto test(F f) -> decltype(((f.operator()((std::declval< ArgList >())...)), int()))
static void call(Function f, Obj *o, void **arg)
static void call(Function f, Obj *o, void **arg)
static void call(Function f, Obj *o, void **arg)
static void call(Function f, void *, void **arg)
static void call(Function f, void *, void **arg)
static void call_internal(void **args, Lambda &&fn) noexcept(noexcept(fn()))
static void call(Func &f, void *, void **arg)
ReturnType(*)(Args...) Function
decltype(std::declval< Func >()(std::declval< Args >()...)) ReturnType
decltype(std::declval< Functor >().operator()((std::declval< ArgList >())...)) Value
makeIndexSequence< N > Value
List_Append< List< typenameL::Car >, typenameList_Left< typenameL::Cdr, N-1 >::Value >::Value Value
void operator()(QSlotObjectBase *p) const noexcept
static void cleanup(QSlotObjectBase *p) noexcept
Definition moc.h:23