Огляд С++11 для Qt-розробників


Стаття не завершена. З часом будуть вноситися зміни та вдосконалення.

Ввімкнення підтримки C++11

  • У компіляторі MSVC підтримка C++11 ввімкнено за замовчуванням
  • Якщо ви використовуєете gcc ви маєте додати параметер -std=c++0x для програми-компілятора
    • У Qt це можна зробити з допомогою наступного фрагменту коду у .pro файлі
       QMAKE_CXXFLAGS += -std=c++0x 
  • У Qt 5 на Linux з остінніми версіями gcc, на Windows з останніми версіями Visual Studio, та на Mac OS X 10.8, просто додайте у .pro-файл
    CONFIG += c++11


Огляд C++11

Наступний фрагмент програми містить порклади для деяких з наступних нововведень C++:

  • “nullptr” keyword
  • Right angle bracket
  • New string literals
  • long long type
  • Initializers lists
  • Uniform initialization
  • Type inference
  • Const expressions
  • Static asserts
  • “override” keyword
  • “final” keyword
  • ”=delete” symantics
  • ”=default” symantics
  • Delegate constructors
  • Lambda functions
  • R-value references and move symantics


#include <iostream>
#include <list>
#include <QString>
#include <QStringList>
 
using namespace std;
 
// ● "nullptr" keyword
const char *const ch = nullptr;
int  *pi = nullptr;   // OK
bool booleanvar = nullptr;   // OK, booleanvar will be set to false.
//int i = nullptr;   // error: can't convert a nullptr to int.
 
// ● Right angle bracket
list<list<int>> gListOfLists;
 
// ● New string literals
QString s1 = "foo";        // Implementation character set string
QString s2 = R"(foo\bar)"; // Raw string, no need to escape backslashes
QString s3 = u8"foo";      // UTF-8 string
QString s4 = u8R"(foo)";   // UTF-8 raw string
QString s5 = QString::fromUtf16(reinterpret_cast<const ushort *>(u"foo"));    // UTF-16 string
QString s6 = QString::fromUtf16(reinterpret_cast<const ushort *>(uR"(foo)")); // UTF-16 raw string - char16_t *
QString s7 = QString::fromUcs4(reinterpret_cast<const uint *>(U"foo"));       // UTF-32 string - char32_t *
QString s8 = QString::fromUcs4(reinterpret_cast<const uint *>(UR"(foo)"));    // UTF-32 raw string
 
// ● long long type
long long gVeryLong = 99999999999999;
 
// ● Initializers lists
class InitTesterPublic
{
public:
    int a;
    char *b;
};
 
InitTesterPublic gIinitTestPublicInstance = {42, "universe"};
 
QStringList fruit{"apple", "pear", "peach", "tomato"};
 
// Or members initialization
//MyClass::MyClass()
//        : _fruit{"apple", "pear", "peach", "tomato"};
//    {
//    }
 
// ● Uniform initialization
class InitTesterInitializer
{
public:
 
 
// *  template<class T> class initializer_list;
// *   This type is used to access the values in a C++ initialization list, which is a list of elements of type const T.
// *   initializer_list objects are automatically constructed as if an array of elements of type T was allocated,
//    with each of the elements in the list being copy-initialized to its corresponding element in the array,
//    using any necessary non-narrowing implicit conversions.
// *   initializer_list object refers to the elements of this array without containing them:
//    copying an initializer_list object produces another object referring to the same underlying elements,
//    not to new copies of them (reference semantics)
//    * The lifetime of this temporary array is the same as the initializer_list object.
 
    InitTesterInitializer(initializer_list<int> list)
    {
        // ....
    }
};
 
// * for classes and structs (before - aggrefate initializatin for classes and structs)
// * passing constructor params in curly brases - regular constructor initialization
// * priorities
//      * Initializer_list constructor
//      * regular constructor that takes parameters
//      * aggregate initializer
 
 
// ● Type inference
// ● Range based "For" loop
 
void autoDemo()
{
    std::list<int> intList;
 
    for (auto iter = intList.begin(); iter != intList.end(); iter++) // Deducts type during compilation
    {
        // ......
    }
 
    for (auto i: intList) // Deducts type during compilation
    {
        // ......
    }
 
 
// instead of following
//    for (std::list<int>::iterator iter = intList.begin(); iter != intList.end(); it++)
//    {
//        // ......
//    }
 
    QStringList options {"a", "b", "c", "d"}; // Initializer lists!
 
   for (const QString & option : options) // Range based "For" loop
   {
       std::cout << qPrintable(option) << std::endl;
   }
}
 
// ● Const expressions
constexpr long constFunc(int i) {return i * i;} // Calculated at compile time!
 
const long longConst = 32 * constFunc(11);
char *theCString[constFunc(3)];
 
// ● Static asserts
void assertDemo()
{
    static_assert( ch == nullptr , "something going wrong" );
}
 
// ● "override" keyword
// ● "final" keyword
// ● "=delete" symantics
// ● "=default" symantics
// ● Delegate constructors
class Foo
{
    public:
        Foo()
        {
            // ........
        }
 
        Foo(int pValue, int pValue2)
            : Foo(pValue, pValue2) // Delegating to another constructor before
        {
            // ......
            qDebug("Waaaaaaaa!!!!!");
        }
 
        void function() {}
};
 
class Bar : public Foo
{
public:
    Bar(int i)
    {
 
    }
 
    void function() =delete;
 
    Bar(const Bar&) =delete;
};
 
// ● Strongly typed enums
enum class Statuses1 {NoError, WrongPassword, InternalServer};
enum class Statuses2 {NoError, WebError};
 
void aaa()
{
    Statuses1 st = Statuses1::NoError;
    if (Statuses1::NoError == Statuses1::NoError)
    {
 
    }
}
 
 
 
auto aaaaa = [=](int a){return a*a;};
 
void bb()
{
    int z = aaaaa(42);
}
 
// ● Lambda functions
// ● R-value references and move symantics
 
int main()
{
    Foo lFoo(1, 0);
 
    cout << "Hello World!" << endl;
 
 
    return 0;
}

C++11 разом з Qt

Макроси у Qt 5, які визначені, якщо компілятор підтримує ті чи інші нововведення з С++11:

  • Q_COMPILER_RVALUE_REFS
  • Q_COMPILER_DECLTYPE
  • Q_COMPILER_VARIADIC_TEMPLATES
  • Q_COMPILER_AUTO_TYPE
  • Q_COMPILER_EXTERN_TEMPLATES
  • Q_COMPILER_DEFAULT_DELETE_MEMBERS
  • Q_COMPILER_CLASS_ENUM
  • Q_COMPILER_INITIALIZER_LISTS
  • Q_COMPILER_LAMBDA
  • Q_COMPILER_UNICODE_STRINGS

Макроси Qt 5, які варто використовувати замість ключових слів С++11:

  • Q_DECL_CONSTEXPR
  • Q_DECL_EXPORT
  • Q_DECL_FINAL
  • Q_DECL_IMPORT
  • Q_DECL_NOEXCEPT
  • Q_DECL_NOEXCEPT_EXPR( x)
  • Q_DECL_NOTHROW
  • Q_DECL_OVERRIDE

Деякі інші особливості Qt5, які варто відмітити:

  • Контейнери з Qt5
    • Можна використовувати списки ініціалізації для наповнення контейнеру початковими значеннями
    • Використовують Move-семантику для оптимізації
  • Range based loops працюють більш оптимально ніж макрос foreach
  • Новий тип сигнально-слотових з'єднань надає змогу приєднувати сигнали до лямбда виразів

Інші зміни, які варто відмітити

Відмітимо кілька з нововведень окремо, про які корисно знати:

  • Підтримка потоків у C++11
    • C++11 має підтримку багатопотокового програмування. Тож тепер не обов'язково використовувати сторонні рішення (наприклад, Boost чи Qt).
  • Підтримка регулярних виразів
    • Можливо, не володіє усіма можливостями класу QRegularExpression (який є новий у Qt 5 на заміну QRegExp у Qt4), але дає можливість працювати з регулярними виразами у програмах, які не використовують Qt та інші сторонні бібліотеки.
  • Нові контейнери STL
    • Такі як array, forward_list, unordered_map, unordered_multimap, unordered_set and unordered_multiset + також деякі нові алгоритми для контейнерів

Посилання на джерела

В останнє змінено: 2015/02/12 10:45