C ++ 14 for Qt programmers

Original author: Olivier Goffart
  • Transfer
This article describes how the changes brought by the C ++ 14 standard have affected or may affect the development of Qt applications. This article is focused not only on Qt programmers, but also on all those who are interested in the development of C ++. The author of the original is Olivier Goffart, one of the developers of Qt moc (meta-object compiler).


Generalized lambda functions


Lambda functions were introduced in C ++ 11, and Qt5 allows them to be used in signals. C ++ 14 simplifies the use of lambda functions, since now the type of arguments can be deduced automatically, that is, it became possible to use auto as a parameter type instead of explicitly describing this type:
connect(sender, &Sender::valueChanged, [=](constauto &newValue) {
       receiver->updateValue("senderValue", newValue);
 });

A lambda function is a functor with an operator () operator implemented. In generalized lambda functions, this operator is declared as a template function. I made changes that support such functors and these changes were included in Qt 5.1. C ++ 14 also adds the ability to capture not only variables, but also expressions:
connect(sender, &Sender::valueChanged, [receiver=getReceiver()](constauto &newValue) {
       receiver->updateValue("senderValue", newValue);
 });


Softening Constant Expression Requirements


In C ++ 11, the new constexpr keyword was introduced. Qt 4.8 introduced the new macro Q_DECL_CONSTEXPR, which expands to constexpr if the word is supported by the compiler. In Qt 5, this macro is used for a large number of functions, where it is only possible.
In C ++ 14, the requirements for constant expressions were relaxed. C ++ 11 allowed using constexpr only with a single return statement and only in member functions with the const modifier. C ++ 14 allows much more, if only the calculation could occur at compile time.
/*
Эта функция не скомпилируется в С++11, потому что состоит из нескольких компонентов, содержит цикл и внутреннюю переменную.
Но в С++14 это разрешено
*/constexprintmyFunction(int v){
  int x = 1;
  while (x < v*v)
    x*=2;
  return x;
}

Class member functions declared as constexpr in C ++ 11 are automatically treated as constant, that is, not changing the fields of the class. In C ++ 14, a non-constant member function of a class can also be constexpr. The result of this change was that class member functions declared by constexpr, but without an explicit const modifier, became non-constant in C ++ 14, which means incompatibility at the binary file level. Fortunately, in Qt, the Q_DECL_CONSTEXPR macro explicitly declared all class member functions to be constant, so there is no violation of binary compatibility when using it.
So, now we can compile non-constant class functions at compile time, such as, for example, operator =. To do this, a new macro Q_DECL_RELAXED_CONSTEXPR will be introduced in Qt 5.5, which will be deployed in constexpr if the compiler is in C ++ 14 mode.

Minor changes in C ++ 14


The C ++ 14 standard has introduced a number of small changes, the purpose of which is to make development more convenient. These changes do not directly affect Qt, but they can be used in your programs if you use a compiler with C ++ 14 support.

Number Separators

If you need to define a large constant in the code, you can use the apostrophe as a separator of digits:
int i = 123'456'789;


Binary constants

In C ++, you can define decimal, octal (starting at 0), and hexadecimal (starting at 0x) constants. Now it is possible to define binary constants using the 0b prefix:
int i = 0b0001'0000'0001;


Automatic return type return

If you have a built-in (inline) function, then you can use the auto keyword as an indication of the return type, now you can not specify it explicitly. The compiler will output it:
// возвращаемый тип будет выведен как 'int'autosum(int a, int b){ return a+b; }

This, unfortunately, is not supported for Qt slots or the so-called invocable methods, since Qt moc is not able to determine the return type itself.

Template Variables

It used to be possible to make a template function or class. Now you can make a template and just a variable.
template<typename T> const T pi = 3.141592653589793;
/*...*/float f = pi<float>;
    double d = pi<double>;


Initialization of Structures

In C ++ 11, it has become possible to initialize a structure that does not have a user-defined constructor with an initialization list (field values ​​in curly brackets), and it has also become possible to set non-static class fields to default values ​​directly in the class definition. But in C ++ 11 it was impossible to use both of these initialization options at once. In C ++ 14 it is now possible. This code will work exactly as expected:
structMyStruct {int x;
    QString str;
    bool flag = false;
    QByteArray str2 = "something";
};
// ...// не скомпилируется в C++11 потому что MyStruct не POD
MyStruct s = { 12, "1234", true };
Q_ASSERT(s.str2 == "something");


Reference Qualifiers for Class Methods


This was actually introduced not in C ++ 14, but also in C ++ 11, but we started using these qualifiers only in Qt5, and I did not mention them in previous posts, so let's talk about them now.
Consider the following code:
QString lower = QString::fromUtf8(data).toLower();

Here fromUtf8 returns a temporary variable. It would be nice if the toLower method used the allocated memory for this temporary variable and performed the necessary transformations in it. Specifically for such cases, link qualifiers for class member functions were introduced.
Simplified code from qstring.h:
classQString {public:
    /* ... */QString toLower()const &
    { /* ... возвращает копию со всеми символами в нижнем регистре ... */ }
    QString toLower() &&
    { /* ... выполняет преобразования в исходной строке ... */ }
    /* ... */
};

Note the '&' and '&&' at the end of the toLower methods. These are link qualifiers and allow you to overload a function depending on the type pointed to by 'this', in the same way that the const qualifier allows you to overload a method depending on the consistency of 'this'. In the case when toLower is called for a temporary variable (rvalue), the second method will be selected (which with &&) and will change the line without copying it.
Functions that were improved with these qualifiers in Qt 5.4: 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 to the Standard Library


C ++ 11 and C ++ 14 have added many constructs to the standard library, which largely overlap with existing constructs in QtCore. Qt uses very little standard library. We generally do not want the standard library to be part of the ABI. This will allow you to remain binary compatible even if the standard library changes (for example, libstdc ++ and libcpp). Qt also still supports some older platforms that do not have the standard C ++ 11 library. For these reasons, we restrict the use of this library.
But there is an exception - Qt5 declares its algorithms deprecated and now it is recommended to use STL algorithms (for example, std :: sort instead of qSort).

Conclusion


Of course, it may take some time before you can use the new C ++ 14 constructs in your projects. But I hope that you will start to apply them like many others (Qt Creator, KDE, LLVM). In the new MSVC compilers, C ++ 14 is active by default, in clang and gcc you need to use a special flag (at the moment this is -std = c ++ 1y). Using qmake, you can configure your project to build with C ++ 14 starting with Qt5.4 using the following command: CONFIG + = c ++ 14

Also popular now: