πŸ“œ ⬆️ ⬇️

C ++ 14 for Qt programmers

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 developing C ++. The original author is Olivier Goffart, one of the developers of Qt moc (meta-object compiler).


Generalized lambda functions


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

A lambda function is a functor with an implemented operator (). 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()](const auto &newValue) { receiver->updateValue("senderValue", newValue); }); 


Mitigating constant expression requirements


In C ++ 11, a new keyword constexpr was introduced. In Qt 4.8, the new macro Q_DECL_CONSTEXPR was introduced, which expands to constexpr if this word is supported by the compiler. In Qt 5, this macro is used for a large number of functions where this is only possible.
In C ++ 14, the requirements for constant expressions were relaxed. C ++ 11 allowed using constexpr only with a single return operator and only in member functions with the const modifier. C ++ 14 allows much more, so long as the computation could occur at compile time.
 /*      ++11,      ,     .   ++14   */ constexpr int myFunction(int v) { int x = 1; while (x < v*v) x*=2; return x; } 

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

Small changes in C ++ 14


Standard C ++ 14 introduced a number of small changes, the purpose of which is to make development more convenient. These changes do not have a direct impact on Qt, but may well 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 an apostrophe as a separator for discharges:
 int i = 123'456'789; 


Binary Constants

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


Automatic output of return type

If you have a built-in (inline) function, then you can use the auto keyword as an indication of the return type, it can now not be explicitly specified. The compiler will output it himself:
 //      'int' auto sum(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 became possible to initialize a structure that does not have a user-defined constructor, initialization list (field values ​​in curly brackets), and also the ability to assign default values ​​to non-static class fields 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:
 struct MyStruct { 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


It 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 already allocated memory for this temporary variable and performed the necessary transformations in it. It is for such cases that reference qualifiers for member functions of classes have been introduced.
Simplified code from qstring.h:
 class QString { public: /* ... */ QString toLower() const & { /* ...         ... */ } QString toLower() && { /* ...      ... */ } /* ... */ }; 

Notice the '&' and '&&' at the end of the toLower methods. These are reference 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 constancy of 'this'. In the case when toLower is called for a temporary variable (rvalue), the second method will be selected (which is with &&) and will make changes to the string without copying it.
Functions that have been enhanced 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 in the standard library


C ++ 11 and C ++ 14 have added many constructs to the standard library, which largely overlap with the existing constructs in QtCore. In Qt, the standard library is used very little. We generally do not want the standard library to be part of ABI. This will allow it 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 limit the use of this library.
But there is an exception - Qt5 declares its algorithms to be obsolete (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 new C ++ 14 constructions in your projects. But I hope that you will start using 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 (currently this is -std = c ++ 1y). With qmake, you can customize your project to build with C ++ 14 starting with Qt5.4 using the following command: CONFIG + = c ++ 14

Source: https://habr.com/ru/post/243981/


All Articles