C++14 for Qt programmers
C++14 is the name of the version of the standard to be released this year. While C++11 has brought many more feature that took time to be implemented by the compilers, C++14 is a much lighter change that is already implemented by compilers such as clang or gcc.
Qt 5 already was adapted in many ways so you can make use of the new features of C++11. You can read about that in my previous article. C++11 in Qt5 . This article mention some of the changes in C++14 and the impact on Qt users.
Generic lambda
C++11 introduced lambda function, and Qt5 allow you to connect signals to them with the
new connect syntax.
C++14 simplify the use of lambda function as the arguments can be automatically deduced.
You can use
auto
as parameter type instead of explicitly writing the type.
connect(sender, &Sender::valueChanged, [=](const auto &newValue) { receiver->updateValue("senderValue", newValue); });
Internally, lambda function is just a functor object with an operator()
.
With generic lamdba, that operator is now a templated function.
I had to make a
change which was included in Qt 5.1 already to support such functors.
C++14 also adds the possibility to have expressions in the capture.
connect(sender, &Sender::valueChanged, [reciever=getReciever()](const auto &newValue) { receiver->updateValue("senderValue", newValue); });
Relaxed Constant expressions
C++11 came with the new constexpr
keyword.
Qt 4.8 has added a new macro Q_DECL_CONSTEXPR
that expands to constexpr
when supported,
and we have been using it for many function when possible in Qt 5.
C++14 is relaxing the rules of what is allowed in a constexpr. C++11 rules were only allowing a single return statement, and could only be applied on const functions. C++14 allow pretty much any code that can be evaluated at compile time.
/* This function was not valid in C++11 because it is composed of several statements, * it has a loop, and a local variable. It is now allowed in C++14 */ constexpr int myFunction(int v) { int x = 1; while (x < v*v) x*=2; return x; }
Member functions declared as constexpr
in C++11 were automatically considered
as const
. It is no longer the case as non-const function can also be constexpr
.
The result of this change is that constexpr
member functions that were not explicitly marked
as const
will change const-ness in C++14, and this is a binary incompatible change.
Fortunately in Qt, all Q_DECL_CONSTEXPR
member functions were also explicitly declared as
const
to keep binary compatibility with non C++11 code.
So now we can start annotating non-const functions such as operator=
of many classes.
For this reason, Qt 5.5 will come with a new macro Q_DECL_RELAXED_CONSTEXPR
which expands to
constexpr
when the compiler is in a C++14 mode. We will then be able to start
annotating relevant functions with Q_DECL_RELAXED_CONSTEXPR
Small features
C++14 also comes with a lot of small convenience feature. That do not have direct impact on Qt, but can
be used in your program if you enable C++14. We just made sure that tools like moc
can
handle them.
Group Separators in Numbers
If you are writing huge constant in your code, you can now now use '
as a group separator:
int i = 123'456'789;
Binary literal
In C++ you can write your number in decimal, octal (starting your number with 0
),
hexadecimal (starting with 0x
). You can now also write in binary by using the 0b
prefix.
int i = 0b0001'0000'0001;
Automatic return type detection
If you have an inline function, you can use auto
as a return type, and
you do no longer need to specify it. The compiler will deduce it for you
// return type auto detected to be 'int' auto sum(int a, int b) { return a+b; }
This is, however, not supported for slot or invokable method as
moc
would not be able to detect the return type
Variable template
You could have functions template or class template. Now you can also have variable template.
template<typename T> const T pi = 3.141592653589793; /*...*/ float f = pi<float>; double d = pi<double>;
Uniform initialization of structures with non static data member initializers
In C++11, you can use the uniform initialization to initialize a struct that has no constructor by initializing all the members. C++11 also added the possibility to have inline non static data member initiazers directly in the class declaration. But you could not use the two at the same time. In C++14, you can. This code works and do what you would expect:
struct MyStruct { int x; QString str; bool flag = false; QByteArray str2 = "something"; }; // ... // did not compile in C++11 because MyStruct was not an "aggregate" MyStruct s = { 12, "1234", true }; Q_ASSERT(s.str2 == "something");
Reference Qualifiers
This is not a C++14 feature, but a C++11 change. But we only started to make use of this late in the Qt5 cycle and I did not mention it in a previous blog post so I'll mention it here.
Consider this code:
QString lower = QString::fromUtf8(data).toLower();
fromUtf8
returns a temporary. It would be nice if the toLower
could re-use the memory allocated by the string and do
the transformation in place. Well that's what the reference qualifiers for member functions are for.
(code simplified from qstring.h:)
class QString { public: /* ... */ QString toLower() const & { /* ... returns a copy with lower case character ... */ } QString toLower() && { /* ... do the conversion in-place ... */ } /* ... */ };
Notice the '&' and '&&' at the end of toLower
. Those are references qualifier and let overload a function depending on the
reference type of the 'this' pointer, just like the const
qualifier let overload on the constness of this.
When toLower is called on a temporary (a rvalue reference) the second overload (the one with &&) will be chosen
and the transformation will be done in place.
The functions that benefit from the optimisation in Qt 5.4 are:
QString::toUpper, QString::toLower, QString::toCaseFolded, QString::toLatin1, QString::toLocal8Bit, QString::toUtf8,
QByteArray::toUpper, QByteArray::toLower, QImage::convertToFormat, QImage::mirorred, QImage::rgbSwapped,
QVersionNumber::normalized, QVersionNumber::segment
Changes in the standard library.
C++11 and C++14 have added a lot of feature to the standard library, competing with many of the features of QtCore. However, Qt makes little use of the standard library. In particular, we do not want to have the standard library as part of the ABI. This would allow to stay binary compatible even when the standard library is changed (example libstdc++ vs. libcpp). Also, Qt still supports older platforms that do not have the C++11 standard library. This really limits our uses.
Yet, Qt5 deprecated its own algorithms library and is now recommending to use the algorithms
from the STL (example, std::sort
instead of qSort
).
Conclusion
It may still take some time before you can use those features in your project. But I hope that, by now, you started using C++11 features like many others projects did (Qt Creator, KDE, LLVM).
MSVC will enables C++14 by default with their new compilers, but clang and gcc require
a special compilation flag (currently -std=c++1y
).
With qmake, you can enable your project to build with C++14 since Qt 5.4 by using this option:
CONFIG += c++14
Woboq is a software company that specializes in development and consulting around Qt and C++. Hire us!
If you like this blog and want to read similar articles, consider subscribing via our RSS feed (Via Google Feedburner, Privacy Policy), by e-mail (Via Google Feedburner, Privacy Policy) or follow us on twitter or add us on G+.
Article posted by Olivier Goffart on 17 November 2014
Click to subscribe via RSS or e-mail on Google Feedburner. (external service).
Click for the privacy policy of Google Feedburner.
Google Analytics Tracking Opt-Out
Loading comments embeds an external widget from disqus.com.
Check disqus privacy policy for more information.