A small new feature that I have added to Qt 5.8 is the possibility of disabling narrowing conversions in the new-style QObject::connect
statement. In this short blog post I would like to share with you why I thought this was useful and therefore implemented it.
The problem
Since Qt 5.0, the new-style, PMF-based (pointer to member function-based) QObject::connect
will check at compile time if the signal's signature is compatible with the slot's one.
For instance, let's consider these two QObject
subclasses:
This is what happens with various connect statements between them:
So far, nothing surprising -- a perfect match between the arguments will make the QObject::connect
statement happy.
Let's try some variations:
Here things become more interesting: since there is no conversion between an int
and a QString
(and vice versa), this code rightfully fails to compile; the same happens with double
.
In this case, the improvement that we get over the "old"-style QObject::connect
is that this error is at compile-time instead of runtime. Indeed, the same connect statements rewritten using the macro-based QObject::connect
will not work and generate warnings on the console. For instance:
The catch
The new QObject::connect
has another little-known interesting feature: it allows the compiler to perform implicit conversions between the arguments of the signal and the slot.
For instance:
This is just not possible at all using the old-style syntax; one would need workarounds such as a "trampoline slot" that does the conversion and emits another signal with the converted argument.
However, having implicit conversions also means that this statement succeeds:
This may be unexpected, as people usually assume this conversion will not work. After all, while converting an int
to a double
is always possible without loss of precision, converting a double
to an int
may lose precision or just not be possible (if the double
is out of range).
Unfortunately, this conversion is fully allowed by C++. Consider it, if you prefer, one of the C remnants in the C++ language. That is, this code:
This is 100% legal C++ that compiles and works as expected (d
is truncated; if it can't fit into an int
, the program has undefined behavior).
Only with C++11 one can forcibly disable narrowing conversions, by using the new uniform initialization syntax (so it's effectively an opt-in feature). For instance:
Although many compilers just warn about this, this C++ code is ill-formed, because of the narrowing conversion from double to int.
Since we don't like dealing with undefined behavior, I wondered if it could be possible to achieve the same for Qt. That is, could we disable implicit narrowing conversions in QObject::connect
?
The solution
I went ahead and implemented the necessary modifications. Starting with Qt 5.8 one can define the QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
macro to disable the implicit conversions that narrow (if you are curious, I implemented it in this patch).
If you are using qmake, add this to your .pro
file:
With this macro defined, QObject::connect
statements that would narrow the arguments do not compile any longer:
This functionality is opt-in, as making it the default (and opt-out) may break valid source code. In the Qt Project we try to never introduce gratuitous source-incompatible changes.
Conclusions
My personal recommendation would be to always define QT_NO_NARROWING_CONVERSIONS_IN_CONNECT in your projects. It will contribute to your projects' "hygiene factor" by removing the possibilities of dangerous connect statements. For this reason, Qt itself uses it on the entirety of its build (see here).
Also, don't forget that the Qt Project is open to contributions. Every time you think "it would be great if Qt could do this little thing for me...", don't be afraid, and contribute to Qt yourself!
Trusted software excellence across embedded and desktop platforms
The KDAB Group is a globally recognized provider for software consulting, development and training, specializing in embedded devices and complex cross-platform desktop applications. In addition to being leading experts in Qt, C++ and 3D technologies for over two decades, KDAB provides deep expertise across the stack, including Linux, Rust and modern UI frameworks. With 100+ employees from 20 countries and offices in Sweden, Germany, USA, France and UK, we serve clients around the world.
2 Comments
12 - Apr - 2017
Tomaz Canabrava
awesome, and I also think that this should be enabled by default.
12 - Apr - 2017
Giuseppe D'Angelo
Hi, I agree, but making it opt-out instead of opt-in is a source incompatible change, and those are frowned upon in Qt; maybe we'll make it opt-out in Qt 6. A discussion of which kind of source incompatible changes are acceptable within the same major version of Qt is going on here: https://codereview.qt-project.org/#/c/182311/ .
Cheers,