diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2022-10-06 12:36:27 +0200 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2022-10-10 20:19:45 +0200 |
commit | fcd294a9ec2a17b3512d03e84ae3560d7fcd3f74 (patch) | |
tree | 0af75d4c92f44194f14e3107d2b3cfcf5a34940d | |
parent | 2ef130a41d26b1b75fe402c398900a05ae381a6a (diff) |
QPrivateSignal: disable implicit conversions from initializer_list
The whole point of QPrivateSignal is to forbid anyone but the class
itself from emitting a certain signal. This is a "workaround" introduced
in Qt 5.0, due to the fact that the PMF syntax for connections requires
users to take the address of a signal, and that is only possible if the
signal itself is public. (In fact, signals were protected in Qt 4.)
The Q_OBJECT macro defines the private QPrivateSignal class. A QObject
subclass that wants to "protect" its signal emissions can declare a
signal carrying an argument of type QPrivateSignal:
signals:
void aSignal(int, QPrivateSignal);
If the class itself wants to emit the signal, it can do so:
emit aSignal(42, QPrivateSignal());
But if "someone else" wants to, they can't use the QPrivateSignal type
because it's private.
emit obj.aSignal(42, SomeClass::QPrivateSignal()); // ERROR
Here's a hair in this soup: list initialization. If a braced-init-list
is used, [over.ics.list] simply *ignores* access control. This allows an
"untyped" initializer-list to match QPrivateSignal and perform aggregate
initialization:
emit obj.aSignal(42, {}); // works!
This kind of defeats the whole purpose. Therefore: make QPrivateSignal
not an aggregate and give it an explicit default constructor, disabling
copy-list-initialization for it. This means that using `{}` will fail to
compile (class is no longer an aggregate, a constructor must be
selected, and copy-list-initialization will not select an explicit
constructor).
This isn't a complete fix by any means. There's always the possibility
of using enough template magic to extract QPrivateSignal's type (e.g. as
a local alias) and then create an object of that type; but that sounds
extremely unlikely to be happening "by accident" (whilst it's super-easy
to just type {} as the argument and not realize that you were not
supposed to do so).
[ChangeLog][QtCore][Potentially Source-Incompatible Changes] It is no
longer possible to use `{}` to construct a QPrivateSignal object
(specifically, QPrivateSignal's default constructor is now explicit).
This means that emitting a signal that carries a QPrivateSignal argument
(i.e. a "private signal") cannot any longer be done by using something
like `emit aSignal({})`; instead, such usages must be ported to
`emit aSignal(QPrivateSignal());` or equivalent.
Change-Id: Iac379aee3a8adca5a91d5db906a61bfcd0abc89f
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r-- | src/corelib/kernel/qtmetamacros.h | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/src/corelib/kernel/qtmetamacros.h b/src/corelib/kernel/qtmetamacros.h index 8a880f34a5..79e3375ed5 100644 --- a/src/corelib/kernel/qtmetamacros.h +++ b/src/corelib/kernel/qtmetamacros.h @@ -127,7 +127,7 @@ private: \ Q_OBJECT_NO_ATTRIBUTES_WARNING \ Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \ QT_WARNING_POP \ - struct QPrivateSignal {}; \ + struct QPrivateSignal { explicit QPrivateSignal() = default; }; \ QT_ANNOTATE_CLASS(qt_qobject, "") /* qmake ignore Q_OBJECT */ |