Qt and C++11

Qt and C++11

Wednesday, September 4, 2013

Introduction

With most C++ compilers now providing good support for the latest language standard, C++11, let's look at some of the new language features that are particularly useful for use in Qt programs. I won't cover all the new C++11 features; just some that in my experience are particularly useful when programming with Qt. See the references at the end if you want more details.

Enabling C++11 Compiler Support

Some compilers need command line options to enable C++11 support. If you are using qmake as your build system, adding the following line to your qmake project file should produce a make file with suitable options for your compiler:

    CONFIG += c++11

This should work with Qt 5.1 on Linux with recent versions of gcc, on Windows with recent releases of Visual Studio, and on Mac OS X 10.8.

A colleague tells me that on Mac OS X 10.8 with Qt 5.0.2, that in addition to the above you may need to add these flags:

    QMAKE_CXXFLAGS += -std=c++11 -stdlib=libc++ -mmacosx-version-min=10.7
    LIBS += -stdlib=libc++ -mmacosx-version-min=10.7

Initializer Lists

The C++11 initializer list feature is useful for initializing objects like QStringLists. For example, rather than using code like:

    QStringList fruit;
    fruit << "apple" << "pear" << "peach" << "tomato";

It can be simplified to:

    QStringList fruit{"apple", "pear", "peach", "tomato"};

In the situation where the variable being initialized is a member variable that needs to be initialized in a constructor, you can often move the initialization out of the constructor body and into the constructor initialization list. So code previously written like this:

    MyClass::MyClass()
    {
        _fruit << "apple" << "pear" << "peach" << "tomato";
    }

can be written more simply as:

    MyClass::MyClass()
        : _fruit{"apple", "pear", "peach", "tomato"};
    {
    }

Range-based for Loop

The new range-based for is much like Qt's foreach macro. So code like this:

    QStringList options{"a", "b", "c", "d"};

    foreach(const QString &option, options) {
        std::cout << qPrintable(option) << std::endl;
    }

can now be written using standard C++ like this:

    QStringList options{"a", "b", "c", "d"};

    for (const QString & option : options) {
        std::cout << qPrintable(option) << std::endl;
    }

There are some differences between using foreach and range-based for. See the blog article listed as reference 6 at the end of this post for more details.

Type Inference

The new auto type lets the compiler deduce the appropriate type. It is particularly useful for iterators and when using range-based for. The previous example can be simplified like this:

    QStringList options{"a", "b", "c", "d"};

    for (auto option : options) {
        std::cout << qPrintable(option) << std::endl;
    }

You can specify const or & when using auto variables.

Incidentally, the keyword auto has existed in C and C++ since the very beginning but was not useful for it's original purpose. The new type inference feature found a new use for it, avoiding the need to add a new reserved word to the language.

New Style connect()

Qt applications typically make heavy use of signals and slots which are connected together at run-time using the connect method. Something Qt developers learn early in their careers is to watch for run-time messages indicating errors in signal/slot connections. Because they are only checked at run time it is easy to make errors in the signal/slot names or arguments.

C++11 allows support for a new syntax of Qt's connect function for connecting signals and slots that performs checking at compile time. This reduces the occurrence of a common type of errors. For example, the following old style connect:

    connect(button, SIGNAL(clicked()), checkbox, SLOT(toggle()));

can now be written as:

    connect(button, &QPushButton::clicked, checkbox, &QCheckBox::toggle);

With the new style of connect, the signal and slots names and arguments are checked at compile time. The older connect format is still supported. The return type of connect is now of type QMetaObject::Connection, whereas before it was a bool.

You can also use C++11 lambda functions as slots and connect them to signals. For example:

    auto mySlot = []() { qDebug() << "This is my slot."; }; // Define a lambda function
    connect(button, &QPushButton::clicked, mySlot);         // and connect a signal to it.

You can even define the lambda function as in-line code in the call to connect, like this:

    connect(button, &QPushButton::clicked, [=]() { qDebug() << "Slot is a lambda function."; });

Threads

While not as comprehensive as the support in Qt, C++11 now has support for threads and concurrent programming. Using C++11 threads can make your programs more portable, which may be desirable, particularly for non-graphical code that may not otherwise depend on Qt.

Regular Expressions

The C++11 standard library now has support for regular expressions. It is not as comprehensive as Qt's QRegularExpression class (which is new in Qt 5 and preferred over the QRegExp class which was in Qt 4). Similar to threads, you may want to use the standard C++ regex class for more portability, if it meets your needs.

nullptr Constant

C++11 adds a new keyword nullptr that indicates a null pointer and should be used rather than 0 or NULL. While a small change, it avoids some problems where a type can be ambiguous or cause unwanted type conversions. You should get into the habit of using it.

Below are some examples of using nullptr:

    char *pc = nullptr;   // OK
    int  *pi = nullptr;   // OK
    bool  bp = nullptr;   // OK, bp will be set to false.
    int i    = nullptr;   // Compile error: can't convert a nullptr to int.

Right Angle Bracket

A quirk of C++ parsing rules was that nested templates needed to have white space between the closing ">" characters to prevent them from being confused with the ">>" operator. That restriction is no longer needed in C++11. So where before you needed to write:

    QList<QMap<QString, int> > list;

you can now write it as:

    QList<QMap<QString, int>> list;

New String Literals

C++11 has support for literal strings using the three different Unicode encoding formats as well as "raw" encoding where the backslash character is interpreted literally, making it easier to specify strings like regular expressions that commonly use a literal backslash. Here are some examples:

    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
    QString s7 = QString::fromUcs4(reinterpret_cast<const uint *>(U"foo"));       // UTF-32 string
    QString s8 = QString::fromUcs4(reinterpret_cast<const uint *>(UR"(foo)"));    // UTF-32 raw string

Unfortunately Qt's QString::fromUtf16() and QString::fromUCs4() methods do not accept UTF-16 and UTF-32 strings directly so type casts are needed.

long long Type

The type long long int is now a standard type that is guaranteed to be 64 bits or larger so it is no longer necessary to use Qt's qlonglong type for portability.

New STL Containers

C++11 introduces some new STL container types: array, forward_list, unordered_map, unordered_multimap, unordered_set and unordered_multiset as well as some new algorithms for containers. While best practice is generally to use Qt's containers, you may choose to use these for portability reasons.

Summary

This post illustrated some of the new C++11 features that are useful for Qt programming. Undoubtedly, there are others neglected to be mentioned here. I encourage you to learn and try out the new features in your own code.

A complete compilable Qt example program that includes most of the features listed here can be downloaded from here. It was tested with g++ 4.7.3 and Clang 3.2.1 (I observed a core dump with the threads code using Clang, but the other features of the program worked).

References

  1. The C++ Programming Language, 4th edition
  2. On-line C++ reference
  3. Wikipedia article on C++11
  4. ICS webcast on C++11
  5. Blog posting on C++11 and Qt 5
  6. Another blog posting on C++11 and Qt

Interested in Qt & QML?

Read more articles from the category Qt & QML

Tags:

About the author

Jeff Tranter

Bio:

Jeff Tranter is a Qt Consulting Manager at ICS. Jeff oversees the architectural and high-level design of software systems for clients. Jeff’s leadership organizes global teams of developers on desktop and embedded applications.