Qt5 中的 C++11 特性概览

原文:Olivier Goffart 发布时间:2012 年 6 月 11 日 原文链接:https://woboq.com/blog/cpp11-in-qt5.html

C++11 是当时最新的 C++ 标准版本,为语言本身引入了大量重要的新特性。

Qt 4.8 是第一个在其 API 中开始使用部分 C++11 特性的 Qt 版本。

在 Qt 4.8 发布之前,我曾写过一篇关于 Qt 4.8 中 C++11 的博客文章,本文将不再重复那些内容。

Qt 5 中,我们进一步扩大了对 C++11 的使用范围。下面将详细介绍 Qt 5 中采用的一些关键 C++11 特性。

 

使用 Lambda 表达式作为槽(slots)

Lambda 表达式是 C++11 引入的一种新语法,用于定义匿名函数。

当需要将一个简短的函数作为参数传递时,Lambda 表达式可以避免为此单独声明一个函数,从而显著减少样板代码。

在 C++11 之前,通常需要通过重载 operator() 的结构体来实现仿函数,这种方式既冗长又影响可读性。

在 Qt 4.8 中,Lambda 已经可以用于部分 QtConcurrent 相关的函数;

而在 Qt 5 中,借助 新的 connect 语法,我们甚至可以直接将 Lambda 表达式用作槽函数。

还记得过去为了一个只有一行代码的槽函数,不得不单独写一个成员函数吗?

现在可以直接在使用的位置定义逻辑,使代码更加直观、易读:

支持 Lambda 表达式的编译器包括:

 

Unicode 字面量与 QStringLiteral

在 C++11 中,可以通过 u"MyString" 的形式直接生成 UTF-16 字符串字面量。

Qt 正是基于这一特性实现了 QStringLiteral

QStringLiteral 是一个宏,用于在编译期初始化 QString,从而避免运行时构造带来的开销。

关于 QStringLiteral 的更多细节,可以参考我之前的相关博客文章。

 

常量表达式:constexpr

C++11 引入了 constexpr 关键字,用于标记可在编译期求值的函数或表达式。

在 Qt 5 中,我们引入了 Q_DECL_CONSTEXPR 宏:

Qt 已经为一些合适的 API(例如 QFlags)添加了该标注,使它们能够用于常量表达式。

示例:

注意:

这里使用了 SomeEnum::Value1 这种作用域限定写法,这在 C++11 中是允许的,而在旧标准中并不支持。

 

编译期断言:static_assert

C++11 提供了 static_assert,用于在编译期检测错误,并给出更清晰的错误信息。

Qt 5 中引入了以下宏:

当编译器支持 static_assert 时,这些宏会直接使用该特性;否则会退化为模板技巧实现。

Qt 在内部大量使用这些宏,以便在 API 被误用时,能提供更友好的编译期错误提示。

 

overridefinal

你是否曾因为以下问题而浪费时间调试?

在 Qt 5 中,可以使用 Q_DECL_OVERRIDE 来标注重写的虚函数:

当编译器支持 C++11 时,Q_DECL_OVERRIDE 会展开为 override;否则为空。

如果函数签名不匹配,编译器会直接报错,例如:

此外,Qt 还提供了 Q_DECL_FINAL,用于标记某个虚函数不能再被重写。

 

Deleted 成员函数(= delete

Qt 引入了 Q_DECL_DELETE 宏,在支持的编译器上会展开为 = delete,用于显式删除函数。

这一特性常用于禁止以下行为:

Qt 在 Q_DISABLE_COPY 宏中使用了该机制。

相比旧版本中通过将函数声明为 private 的方式,= delete 能提供更直观、清晰的编译错误信息。

 

右值引用与移动构造函数

在之前关于 Qt 4.8 的文章中,我已经介绍过右值引用的基本概念。

在 Qt 5 中,由于共享类内部引用计数实现的调整,我们得以为许多 Qt 类型添加了 移动构造函数,从而显著提升性能,减少不必要的拷贝。

 

总结

如果你使用 qmake,可以在 .pro 文件中添加:

在 Qt 4 中通常需要写成:gcc:CXXFLAGS += -std=c++0x

现在,你可以尽情享受 C++11 带来的各种优秀特性了——

哪怕只是为了能用 auto,也已经非常值得升级了。