[转载] Qt5中的C++11


原文链接

C++11 in Qt5

C++11 is the name of the current version of the C++ standard, which brings many new features to the language.

Qt 4.8 was the first version of Qt that started to make use of some of the new C++11 features  in its API. I wrote a blog post about C++11 in Qt 4.8  before the 4.8 release which I won’t repeat here.

In Qt5, we make use of even more features. I will go into detail about some of them in this post.

Lambda expressions for slots

Lambda expressions are a new syntax in C++11 which allow to declare anonymous functions. Anonymous functions can be used in order to use small functions as parameter without requiring to explicitly declare them. The previous way to write functors using  operator() in a struct was requiring a lot of boilerplate code.

It was already possible in Qt 4.8 to use lambda expressions in some QtConcurrent functions. Now it is even possible to use them as slots using the  new connect syntax.

Remember the time when you had to write a one-line function for your slot. Now you can write it right in place. It is much more readable to have the function directly where you reference it:

//hack by me for plugin issue
(sender, &Sender::valueChanged, [=](const QString &newValue) {receiver->updateValue("senderValue", newValue);});

Lambda functions are supported since MSVC 2010, GCC 4.5, and clang 3.1.

Unicode literal

In C++11, you can generate UTF-16 by writing u"MyString" . This is used by Qt to implement QStringLiteral which is a macro that initializes the QString at compile time without run-time overhead.
QString someString = QStringLiteral("Hello");

See my previous blog about QStringLiteral.

Constant expressions: constexpr

This new constexpr C++11 keyword can be added to annotate some inline functions to specify that they could be computed at compile time. In Qt 5, we introduced Q_DECL_CONSTEXPR     which is defined to constexpr when the compiler supports it, or nothing otherwise.

enum SomeEnum { Value1, Value2, Value3 };
Q_DECLARE_OPERATORS_FOR_FLAGS(QFlags<SomeEnum>;)
// The previous line declares
// Q_DECL_CONSTEXPR QFlags<SomeValue>; operator|(SomeValue,SomeValue) {...}

int someFunction(QFlags<SomeEnum>; value) {
    switch (value) {
        case SomeEnum::Value1:
            return 1;
        case SomeEnum::Value2:
            return 2;
        case SomeEnum::Value1 | SomeEnum::Value3:
        // Only possible with C++11 and because QFlags operators are constexpr
        // Previously this line would call
        //        QFlags<SomeValue>; operator|(SomeValue,SomeValue)
        // that would have thrown an error because only compiler constants
        // are allowed as case satement

            return 3;
        default:
            return 0;
    }
}

We also annotated some of the Qt functions that made sense (for example QFlags), which allows them to be used in constant expressions. (Notice also here that I used SomeEnum:: in front of the values, which is allowed in C++11,     but was not allowed before)

static_assert

C++11 helps producing better error messages when something wrong can be detected at compile time using static_assert.  In Qt5 we introduced the macros Q_STATIC_ASSERT, and Q_STATIC_ASSERT_X That will use static_assert if available, or some other template trick if not.

Qt uses that macro already quite a lot in order to provide better compiler errors when the API is not used properly.

Override and final

Have you ever had code that did not work because you had a typo in the name of a virtual function you re-implemented? (Or forgot that damn const at the end)

You can now annotate the functions that are meant to override virtual functions with Q_DECL_OVERRIDE.

That macro will be substituted to the new “override” attribute if the compilers supports it, or to nothing otherwise. If you compile your code with C++11 enabled compiler you will get an error if you have a typo, or if you changed a virtual method while re-factoring.


class MyModel : public QStringListModel {
    //...
protected:
     Qt::ItemFlags flags (const QModelIndex &amp; index)  Q_DECL_OVERRIDE;
};

And because we forgot the const that will produce errors such as:


mymodel.h:15: error: `Qt::ItemFlags MyModel::flags(const QModelIndex*)` marked override, but does not override

There is also Q_DECL_FINAL that is substituted to the final attribute which specifies a virtual function cannot be overridden.

Deleted member

The new macro Q_DECL_DELETE expands to = delete for compilers that support deleted functions. This us useful to give better compiler errors to avoid common mistakes.

Deleted functions are used to explicitly delete the function that would be otherwise ceated automatically by the compiler (such as a default constructor, or a copy assignement operator). Deleted functions may not be called and a compiler error is thrown if they are used.

We use it for example in the Q_DISABLE_COPY macro. Before, the trick was to keep those members private, but the error message was not as good.

Rvalue References and Move Constructors

In the Qt 4.8 article I already explained what rvalue references are about.

Due to a change of the internals of the reference counting of our shared class in Qt5, it was possible to add a move constructor for many of them.

Conclusion

MSVC does not require any special flags and enables the C++11 features by default, but GCC or Clang require -std=c++0x.

By default, Qt5 itself will be compiled with the C++11 flags on compilers that need it.

If you use qmake, you can add that line to your .pro file (Qt5):

CONFIG += c++11

(In Qt4, it should be something like: gcc:CXXFLAGS += -std=c++0x)

And now you can enjoy all the nice features of C++11. (It is already worth doing it only for being able to use auto)

comments powered by Disqus