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, by e-mail or follow us on twitter or add us on G+.

Submit on reddit Submit on reddit Tweet about it Share on Facebook Post on Google+

Article posted by Olivier Goffart on 17 November 2014

Get notified when we post a new interesting article!

© 2016 Woboq GmbH