QObject::connect
which take the pointersto functions as arguments instead of char*
QObject::connect
: (not actual code)&
before the name of the signal in your connect call. But you will not need to cope with the ::*
, .*
or ->*
cryptic operators.void*
because they have a different sizeof
.void (MyClass::*)(int) const
tovoid (MyClass::*)(int)
is not allowed.(You could do it with reinterpret_cast; but that would be an undefined behaviour if you callthem, according to the standard)this
in case of multiple inheritance.sizeof
of a pointer to a member function can evenvary depending of the class.This is why we need to take special care when manipulating them.QtPrivate::FunctionPointer
QtPrivate::FunctionPointer
type trait.template<typename T> struct FunctionPointer
will give us informationabout T via its member.ArgumentCount
: An integer representing the number of arguments of the function.Object
: Exists only for pointer to member function. It is a typedef to the class of which the function is a member.Arguments
: Represents the list of argument. It is a typedef to a meta-programming list.call(T &function, QObject *receiver, void **args)
: A static function that will call the function, applying the given parameters.FunctionPointer
lies inqobjectdefs_impl.h.QObject::connect
sender
and receiver
are not just QObject*
as the documentation points out. They are pointers totypename FunctionPointer::Object
instead.This uses SFINAEto make this overload only enabled for pointers to member functionsbecause the Object
only exists in FunctionPointer
ifthe type is a pointer to member function. Q_STATIC_ASSERT
.They should generate sensible compilation error messages when the user made a mistake.If the user did something wrong, it is important that he/she sees an error hereand not in the soup of template code in the _impl.h
files.We want to hide the underlying implementation from the user who should not needto care about it.QSlotObject
that is going to be passed to connectImpl()
.The QSlotObject
is a wrapper around the slot that will help calling it. It alsoknows the type of the signal arguments so it can do the proper type conversion.List_Left
to only pass the same number as argument as the slot, which allows connectinga signal with many arguments to a slot with less arguments.QObject::connectImpl
is the private internal functionthat will perform the connection.It is similar to the original syntax, the difference is that instead of storing amethod index in the QObjectPrivate::Connection
structure,we store a pointer to the QSlotObjectBase
.&slot
as a void**
is only tobe able to compare it if the type is Qt::UniqueConnection
.&signal
as a void**
.It is a pointer to the member function pointer. (Yes, a pointer to the pointer)qt_static_metacall
that compares the parameter and returns the right index.connectImpl
will call the qt_static_metacall
function with thepointer to the function pointer.QSlotObjectBase
is the object passed to connectImpl
that represents the slot.QSlotObject
, QStaticSlotObject
orQFunctorSlotObject
template class.QSlotObjectBase
was changed not to be a C++ polymorphic class.Virtual functions are emulated by hand.m_impl
is a (normal) function pointer which performsthe three operations that were previously virtual functions. The 're-implementations'set it to their own implementation in the constructor.connect
would generate a new different type (since the QSlotObject has template parameterswich depend on signature of the signal and the slot).protected
in Qt4 and before. It was a design choice as signals should be emittedby the object when its change its state. They should not be emitted fromoutside the object and calling a signal on another object is almost always a bad idea.&Counter::valueChanged
would generate a compiler errorif the signal was not public.protected
to public
.This is unfortunate since this mean anyone can emit the signals.We found no way around it. We tried a trick with the emit keyword. We tried returning a special value.But nothing worked.I believe that the advantages of the new syntax overcome the problem that signals are now public.QAbstractItemModel
, where otherwise, developers tend to emit signalfrom the derived class which is not what the API wants.There used to be a pre-processor trick that made signals privatebut it broke the new connection syntax.QPrivateSignal
is a dummy (empty) struct declared private in the Q_OBJECTmacro. It can be used as the last parameter of the signal. Because it is private, only the objecthas the right to construct it for calling the signal.MOC will ignore the QPrivateSignal last argument while generating signature information.See qabstractitemmodel.h for an example.FunctionPointer::Arguments
is a listof the arguments. The code needs to operate on that list:iterate over each element, take only a part of it or select a given item.QtPrivate::List
that can represent a list of types. Some helpers to operate on it areQtPrivate::List_Select
andQtPrivate::List_Left
, which give the N-th element in the list and a sub-list containingthe N first elements.List
is different for compilers that support variadic templates and compilers that do not.template<typename... T> struct List;
. The list of arguments is just encapsulatedin the template parameters.(int, QString, QObject*)
would simply be:template<typename Head, typename Tail > struct List;
where Tail
can be either another List
or void
for the end of the list.FunctionPointer::call
, the args[0]
is meant to receive the return value of the slot.If the signal returns a value, it is a pointer to an object of the return type ofthe signal, else, it is 0.If the slot returns a value, we need to copy it in arg[0]
. If it returns void
, we do nothing.void
.Should I have duplicated the already huge amount of code duplication: once for the voidreturn type and the other for the non-void?No, thanks to the comma operator.void
:void*
. Then it can be usedin each helper. This is for example the case of a functor without arguments: