# 现代 C++ 速览（C++11 / 14 / 17）

> 适用对象：已掌握 C++ 基础语法与面向对象概念、正在向「现代 C++」迁移的学习者。
> 本仓库的编译基线是 **C++17**（见顶层 `CMakeLists.txt`），因此本文所有示例均可在
> `-std=c++17` 下直接编译。每个特性标注引入版本：`C++11` `C++14` `C++17`。
>
> 配套材料：版本相关的「编译期」对照演示见
> [`docs/VERSION_NOTES.md`](../VERSION_NOTES.md) 与 `tools/demo_versions/`；
> 本文聚焦「现代 C++ 是什么、为什么、怎么用」。

---

## 0. 为什么把 C++11 叫做「分水岭」

在 2011 年之前，C++ 标准只有 C++98 和它的缺陷修复版 C++03。从 **C++11** 开始，标准
委员会改为**三年一个发布周期**，此后 C++14、C++17、C++20、C++23… 节奏稳定。

| 版本 | 年份 | 定位 | 一句话概括 |
|---|---|---|---|
| C++98/03 | 1998/2003 | 初代 + 修勘 | 经典 C++：手动内存管理、裸指针、深拷贝 |
| **C++11** | 2011 | **大革命** | 几乎像一门新语言：auto、移动、智能指针、lambda、并发、模板增强 |
| **C++14** | 2014 | 小完善 | 填坑：`make_unique`、泛型 lambda、`decltype(auto)` |
| **C++17** | 2017 | 中等增量 | 实用大件：结构化绑定、`string_view`/`optional`/`variant`、`filesystem`、`if constexpr` |
| C++20 | 2020 | 又一次大改 | 概念、范围、协程、模块（本文不展开） |

**「现代 C++」的三个核心心智模型**（贯穿全文）：

1. **RAII 优先**：资源 = 对象的生命周期，用析构函数自动释放，少写 `new`/`delete`。
2. **值类别与移动**：值不只是「拷贝」，还有「移动」——别再无谓地拷贝临时对象。
3. **编译期能做多少做多少**：`constexpr`、`static_assert`、类型推导，把工作前移。

---

## 1. 类型推导：让代码少写类型名

### 1.1 `auto` `C++11`

```cpp
auto i = 42;                 // int
auto& r = i;                 // int&（显式加 & 才保留引用）
const auto& cr = i;          // const int&
auto p = std::make_pair(1, 2.0);  // 不用写 std::pair<int,double>

for (auto& x : vec) { x *= 2; }   // 范围 for（也是 C++11）
```

**核心概念**：`auto` 的推导规则**与模板参数推导完全一致**——会**丢弃顶层 const 和引用**。
所以要保留引用/const 必须显式写 `auto&` / `const auto&`。

**常见的坑**：
- `auto x = expr;` 几乎总是「拷贝」。想要引用必须写 `&`，想要只读加 `const`。
- `auto&&` 在推导语境是「转发引用」（见 §3），不是固定右值引用。
- `auto` 不能用于数组、不能用于非静态成员的类型……推导不出就报错，通常很友好。

### 1.2 `decltype` `C++11`

```cpp
int x = 1;
decltype(x)   a;   // int   —— 变量名 → 该变量类型
decltype((x)) b;   // int&  —— 加括号 → 左值表达式 → 引用！
```

**核心概念**：`decltype(变量名)` 给类型；`decltype((变量名))`（**带括号**）给引用。这一对括号
的差异是最常见的考点。`decltype` 适合「我想要和某个表达式一模一样的类型，包括 const/引用」。

### 1.3 返回类型推导 `C++14`

```cpp
auto square(int x) { return x * x; }     // C++14：返回类型由 return 推导

template<typename T, typename U>
auto add(T a, U b) { return a + b; }      // 模板里尤其好用
```

> C++11 只能写**尾随返回类型**：`auto f(int x) -> int { ... }`。C++14 起可直接 `auto`。

### 1.4 `decltype(auto)` `C++14`

```cpp
decltype(auto) f() { return some_expr; }  // 用 decltype 规则推导，保留引用/const
```

解决「`auto` 会丢引用」的场景，常用于转发包装器、属性 getter。

### 1.5 结构化绑定 `C++17`

```cpp
std::pair p = {1, std::string("hi")};
auto [id, name] = p;          // id=1, name="hi"

for (const auto& [key, val] : my_map) {   // 遍历 map 终于不丑了
    std::cout << key << " => " << val << "\n";
}

struct Point { int x, y; };
auto [px, py] = Point{3, 4};  // 也能绑定公开成员
```

**核心概念**：一次性把聚合/`pair`/`tuple`/数组的多个元素「拆」给若干变量，替代难看的
`std::get<0>(...)` 或 `.first/.second`。

---

## 2. 移动语义与完美转发：别再无谓拷贝

### 2.1 右值引用与移动构造 `C++11`

```cpp
class Buffer {
    char* data_; size_t n_;
public:
    Buffer(size_t n) : data_(new char[n]), n_(n) {}
    ~Buffer() { delete[] data_; }

    // 移动构造：窃取资源，把源对象置空
    Buffer(Buffer&& o) noexcept : data_(o.data_), n_(o.n_) {
        o.data_ = nullptr; o.n_ = 0;
    }
    Buffer& operator=(Buffer&& o) noexcept { /* 类似 */ return *this; }

    // 拷贝（深拷贝）照常保留
    Buffer(const Buffer& o) : data_(new char[o.n_]), n_(o.n_) {
        std::memcpy(data_, o.data_, n_);
    }
};
```

**核心概念**：
- **左值 (lvalue)** 有名字、可取地址（如变量 `x`）；**右值 (rvalue)** 是临时值（如 `Buffer(64)`、`std::move(x)`）。
- 右值引用 `T&&` 只绑定右值，表示「这个值马上要销毁，资源可以偷走」。
- 移动 = 「偷指针」而非「拷贝内容」，对 `vector`/`string`/`Buffer` 这类持堆资源的类型是巨大提速。

**`std::move` 的真相**：它**什么都不 move**，只是把左值**强制转换**成右值引用 (`static_cast<T&&>`)，
从而允许移动构造/赋值被选中。

```cpp
Buffer a(64);
Buffer b = std::move(a);   // 调用移动构造，a 变成空壳（仍需析构，但便宜）
```

**常见的坑**：
- 移动后的对象处于「有效但未指定」状态，只能析构或重新赋值，不要继续读它。
- 移动构造/赋值**强烈建议标 `noexcept`**：否则 `vector` 扩容时为安全起见会退回拷贝。
- 不要对 `return x;` 里的局部变量写 `std::move(x)`——会**阻止**编译器的 RVO/隐式移动，反而更差。

### 2.2 完美转发 `C++11`

让包装函数把参数「原封不动」（保留 lvalue/rvalue、const）转交给目标函数。三块基石：

1. **转发引用** `T&&`（仅在模板推导语境，绑定 lvalue 与 rvalue）。
2. **引用折叠**：`& + && = &`、`&& + && = &&` 等，让 `T` 编码了实参类别。
3. **`std::forward<T>(x)`**：依据 `T` 把 `x` 还原成正确的值类别。

```cpp
template<typename T, typename Arg>
T my_make(Arg&& arg) {
    return T(std::forward<Arg>(arg));   // 左值→拷贝，右值→移动，自动选对
}
```

**典型应用**：`std::make_unique` / `make_shared`、容器的 `emplace_back`（原地构造，省一次拷贝/移动）。

> 关于 `T&&` 何时是「转发引用」、何时是「纯右值引用」，详见 §10.4 与配套课件。

---

## 3. 智能指针：RAII 的现代化 `C++11`（`make_unique` 为 `C++14`）

裸 `new`/`delete` 是现代 C++ 里**基本不该手写**的东西。三个智能指针各司其职：

| 类型 | 语义 | 开销 | 典型用途 |
|---|---|---|---|
| `std::unique_ptr<T>` | **独占**所有权，不可拷贝、可移动 | 几乎为零（默认等同裸指针） | **默认首选**；工厂返回、类成员持有资源 |
| `std::shared_ptr<T>` | **共享**所有权，引用计数 | 控制块 + 原子计数 | 多处需要共同拥有一同一对象、所有权不唯一时 |
| `std::weak_ptr<T>` | 观察 `shared_ptr`，不增加计数 | 一个指针 | 打破 `shared_ptr` 循环引用、缓存 |

```cpp
// C++14：用 make_unique，异常安全、避免裸 new
auto p = std::make_unique<Widget>(args...);

std::vector<std::unique_ptr<Shape>> shapes;
shapes.push_back(std::make_unique<Circle>(1.0));
shapes.push_back(std::make_unique<Square>(2.0));

auto shared = std::make_shared<Widget>();   // 一次堆分配（对象+控制块）
std::weak_ptr<Widget> observer = shared;    // 不延长生命周期
if (auto locked = observer.lock()) { /* 仍然存活时使用 */ }
```

**核心概念**：析构即释放——`unique_ptr` 出作用域自动 `delete`，`shared_ptr` 计数归零自动 `delete`。
异常发生时栈展开也会调用析构，**资源不泄漏**。这就是 RAII（Resource Acquisition Is Initialization）。

**常见的坑**：
- `make_unique` 是 **C++14** 才有的；C++11 只能 `std::unique_ptr<T>(new T(...))`。
- `shared_ptr` 的控制块是**每个对象一份**——用同一个裸指针构造两个 `shared_ptr` 会产生两个控制块，双重释放：
  ```cpp
  Widget* raw = new Widget;
  std::shared_ptr<Widget> a(raw);   // ❌ 危险
  std::shared_ptr<Widget> b(raw);   // ❌ 两个独立计数 → double free
  ```
- `shared_ptr` 循环引用（A 持有 B，B 持有 A）会泄漏，一端改用 `weak_ptr` 打环。
- `shared_ptr` 线程安全**仅限引用计数操作**；指向的对象本身仍需另行同步。

> 历史：C++98 的 `std::auto_ptr` 因拷贝即「窃取」语义有坑，**C++17 已完全移除**。

---

## 4. Lambda 表达式：就地写函数对象

### 4.1 基本语法 `C++11`

```cpp
[capture](params) mutable -> return_type { body }

auto add = [](int a, int b) { return a + b; };   // 就地定义一个函数对象
add(1, 2);   // 3

std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });  // 降序

int factor = 3;
std::transform(v.begin(), v.end(), v.begin(),
               [factor](int x) { return x * factor; });   // 捕获 factor（按值）
```

**捕获方式**：
- `[]` 不捕获；`[=]` 按值捕获所有用到的；`[&]` 按引用捕获所有用到的；
- `[x]` 按值捕获 `x`；`[&x]` 按引用捕获 `x`；`[this]` 捕获当前对象指针（成员函数内常用）；
- `[=, &x]` 默认按值，但 `x` 按引用。

**核心概念**：lambda 本质是编译器生成的**匿名类（函数对象）**，捕获即成员变量。这让 STL
算法从「写个函数对象/函数指针」解脱出来，可以**就地表达**比较、变换、过滤逻辑。

**常见的坑**：
- `[&]` 捕获引用时，lambda 比 captured 变量活得久（如存进 `std::function` 后异步用）→ 悬垂引用。
- 按值捕获默认使 lambda 为 `const`，要修改捕获的副本需加 `mutable`。
- 捕获 `this` 后，对象被销毁再调用 lambda → 悬垂。

### 4.2 泛型 lambda `C++14`

```cpp
auto plus = [](auto a, auto b) { return a + b; };   // 参数可用 auto
plus(1, 2);        // 3
plus(std::string("a"), std::string("b"));  // "ab"
```

### 4.3 `constexpr` lambda `C++17`

```cpp
constexpr auto sq = [](int x) { return x * x; };
static_assert(sq(5) == 25);   // 编译期可调用
```

---

## 5. 强类型与统一初始化

### 5.1 `nullptr` 取代 `NULL` `C++11`

```cpp
void f(int);
void f(char*);
f(0);          // 调 f(int) —— 0 是 int！
f(NULL);       // 仍可能调 f(int)（NULL 的定义各不相同），坑
f(nullptr);    // 一定调 f(char*) —— nullptr 是独立的 std::nullptr_t 类型
```

**核心概念**：`nullptr` 是**带类型**的空指针字面量，彻底消除「`NULL` 在重载时被当成整数」的经典歧义。

### 5.2 强类型枚举 `enum class` `C++11`

```cpp
enum class Color { Red, Green, Blue };   // 不会污染外层作用域
Color c = Color::Red;
// int i = c;          // ❌ 不能隐式转 int（这正是想要的安全性）
int i = static_cast<int>(c);   // ✅ 显式才行

enum OldColor { Red, Green };  // 旧式：Red/Green 泄漏到外层；可隐式转 int
```

**核心概念**：`enum class`（scoped enum）的作用域封闭、不隐式转换，比 C 风格 enum 安全得多。
还能指定底层类型：`enum class Color : uint8_t { ... };`。

### 5.3 统一初始化（花括号）`C++11`

```cpp
int a[]{1, 2, 3};
std::vector<int> v{1, 2, 3, 4};
std::map<int, std::string> m{{1, "a"}, {2, "b"}};
Point p{3, 4};
Widget w{};                 // 默认构造
```

**核心概念**：`{}` 是统一的初始化语法，适用于容器、聚合、普通对象；还能**窄化检查**
（`int{3.14}` 编译失败，而 `int(3.14)` 截断通过）。

**常见的坑（most vexing parse）**：
```cpp
Widget w();     // ❓ 被解析成「返回 Widget 的函数 w 的声明」！
Widget w2{};    // ✅ 用花括号消除歧义，才是默认构造
```
花括号还能防窄化，但也引入新的歧义（与 `std::initializer_list` 构造函数的偏好），故现代风格里
**简单值用 `=`、聚合/容器用 `{}`**，二者并存。

---

## 6. 类与面向对象的增强

| 特性 | 版本 | 作用 |
|---|---|---|
| `= default` / `= delete` | `C++11` | 显式要求/禁止某个特殊成员函数 |
| `override` / `final` | `C++11` | 让编译器帮你检查虚函数重写、禁止进一步派生 |
| 委托构造 | `C++11` | 一个构造函数调用同类的另一个构造函数 |
| 继承构造 | `C++11`（C++17 调整语义） | `using Base::Base;` 复用基类构造函数 |
| `inline` 变量 | `C++17` | 头文件里直接定义全局/静态变量，不再需要「声明+定义分离」 |

```cpp
struct NonCopyable {
    NonCopyable() = default;
    NonCopyable(const NonCopyable&) = delete;             // 禁止拷贝
    NonCopyable& operator=(const NonCopyable&) = delete;
};

struct Base {
    virtual void f();
    virtual void g() final;     // 子类不能再覆盖 g
};
struct Derived : Base {
    void f() override;          // ✅ 签名必须匹配，拼错或签名不符会编译报错
    // void f() const override; // ❌ 与基类签名不符 → 编译错误（这正是 override 的价值）
};

struct A {
    int x;
    A(int x) : x(x) {}
    A() : A(0) {}               // 委托构造：调用 A(int)
};

// C++17 inline 变量：头文件里安全地定义
struct Counter {
    inline static int instances = 0;   // 不再是「声明」，所有 TU 共享一份
    Counter() { ++instances; }
};
```

**核心概念**：
- `override` 是**编译期契约**：你以为重写了，编译器没报错就一定是真重写了——杜绝「签名笔误导致隐藏而非重写」的隐蔽 bug。
- `= delete` 用**意图清晰的方式**禁用函数，比「声明为 private 且不实现」更直接。
- C++17 `inline` 变量终结了「头文件只能声明、定义放 cpp」的繁琐，对常量、单例尤其友好。

---

## 7. 模板的增强

### 7.1 可变参数模板 `C++11`

```cpp
template<typename... Args>
void print(Args... args) {
    (std::cout << ... << args) << "\n";   // ← 这是 C++17 折叠表达式，见 7.4
}
print(1, " + ", 2, " = ", 3);
```

`typename... Args` 是「模板参数包」，`Args... args` 是「函数参数包」。C++11 里展开包要用
递归模板，比较繁琐。

### 7.2 别名模板 `using` `C++11`

```cpp
template<typename T> using Vec = std::vector<T>;
Vec<int> v;                          // 等价 std::vector<int>

using StringList = std::vector<std::string>;   // 也取代 typedef，更直观
```

`using` 比 `typedef` 强在能模板化，且读起来「左到右」更自然。

### 7.3 `if constexpr` `C++17`

```cpp
template<typename T>
auto get_value(T t) {
    if constexpr (std::is_pointer_v<T>)
        return *t;          // 仅当 T 是指针时才编译这一支
    else
        return t;
}
```

**核心概念**：`if constexpr` 在**编译期**按条件**丢弃**不成立的分支（不实例化）。
替代了以前必须用模板特化/SFINAE 才能实现的「按类型分支」。

### 7.4 折叠表达式 `C++17`

```cpp
template<typename... Args>
auto sum(Args... args) { return (args + ...); }          // 一元右折叠
template<typename... Args>
auto sum2(Args... args) { return (0 + ... + args); }     // 二元，带初值

sum(1, 2, 3, 4);   // 10
```

让可变参数模板的「包展开」从递归套路变成一行，是 C++17 最受好评的小特性之一。

### 7.5 类模板参数推导 CTAD `C++17`

```cpp
std::pair p(1, 2.0);          // 推导出 std::pair<int, double>，无需写模板参数
std::vector v = {1, 2, 3};    // std::vector<int>
std::lock_guard lk(mtx);      // 不用写 std::lock_guard<std::mutex>
```

> 对 Qt 用户：`QSignalMapper` 之类的繁冗模板写法在 C++17 下可显著简化。

---

## 8. `constexpr`：编译期计算

`constexpr` 表示「**可能在编译期求值**」。从 C++11 到 C++17 限制逐步放开：

| 版本 | 能力 |
|---|---|
| `C++11` | 函数体**单条 return**；变量可用常量表达式初始化 |
| `C++14` | 允许循环、局部变量、多语句、`if`/`switch` |
| `C++17` | `if constexpr`；`constexpr` lambda；更多标准库函数（如 `std::array` 的部分操作）标记 constexpr |

```cpp
constexpr int factorial(int n) {           // C++14 起可写循环
    int r = 1;
    for (int i = 2; i <= n; ++i) r *= i;
    return r;
}

int main() {
    constexpr int x = factorial(5);        // 编译期求值
    int arr[factorial(4)];                 // 数组大小，编译期确定
    static_assert(factorial(3) == 6);
    int n; std::cin >> n;
    int y = factorial(n);                  // 也可运行期调用（同一函数两用）
}
```

**核心概念**：`constexpr` 函数「能在编译期就算编译期，不能就退回运行期」——同一份代码两用，
避免「一份宏/模板元编程 + 一份运行函数」的重复。

**`static_assert` `C++11`（无消息版本 `C++17`）**：编译期断言，失败即编译错误。
```cpp
static_assert(sizeof(int) >= 4, "需要 32 位 int");
static_assert(true);              // C++17：可省略消息
```

---

## 9. 标准库的新组件

### 9.1 容器与算法增强

| 组件 | 版本 | 要点 |
|---|---|---|
| `std::array` | `C++11` | 固定大小、栈上、零开销数组（比裸数组更安全、有迭代器） |
| `std::tuple` | `C++11` | 异构类型打包；C++17 配结构化绑定拆解 |
| `std::unordered_map`/`unordered_set` | `C++11` | 哈希表，O(1) 平均查找 |
| `emplace` / `emplace_back` | `C++11` | 原地构造，省一次拷贝/移动（完美转发的直接受益者） |
| `std::initializer_list` | `C++11` | 让 `{1,2,3}` 能作为构造/赋值参数 |
| `std::move`（算法版）/ `std::move_backward` | `C++11` | 用移动而非拷贝在区间间搬运 |
| 透明比较器 `std::less<>` | `C++14` | 异构查找，`map<string,int>` 可用字符串字面量查而免构造 `string` |

```cpp
std::map<std::string, int, std::less<>> m;   // C++14 透明比较
m.find("key");   // 直接用 const char* 查，不构造临时 string
```

### 9.2 C++17 的「实用三件套」+ 文件系统

```cpp
#include <optional>
#include <variant>
#include <string_view>
#include <filesystem>

// optional：可能没有值
std::optional<int> parse(std::string_view s) {
    int v{};
    /* ... */
    return v;            // 有值
    return std::nullopt; // 无值
}
if (auto r = parse("42")) use(*r);

// variant：类型安全的联合，替代 union
std::variant<int, double, std::string> v = "hello";
v = 3.14;
std::visit([](auto&& x) { std::cout << x; }, v);   // 配 lambda 模式匹配

// string_view：不拷贝的字符串「视图」
void log(std::string_view msg);   // 接收 const char*、std::string、子串都不分配

// filesystem：跨平台文件操作（前身 boost::filesystem）
namespace fs = std::filesystem;
for (const auto& e : fs::directory_iterator("/tmp"))
    std::cout << e.path() << "\n";
fs::create_directories("a/b/c");
auto sz = fs::file_size("main.cpp");
```

**核心概念**：
- `optional`/`variant`/`any` 让「这个值可能不存在 / 可能是多种类型之一 / 任意类型」**进入类型系统**，
  编译器帮你保证访问安全，取代裸指针 + 约定、`union` + tag 的脆弱写法。
- `string_view` 是**只读视图**，构造零开销——适合函数参数；但**不拥有**数据，调用方必须保证源串存活。
- `filesystem` 让文件操作不再依赖 `<dirent.h>`/`<windows.h>`，一份代码跨平台。

**常见的坑**：
- `string_view` 不保证以 `\0` 结尾，别直接传给需要 C 字符串的 API（要用 `.data()` 且确认有终止符）。
- `variant` 默认构造为**第一个备选类型**的值，访问时类型不对会抛 `std::bad_variant_access`（或用 `std::get_if`）。

### 9.3 并发支持

| 组件 | 版本 | 作用 |
|---|---|---|
| `std::thread` | `C++11` | 跨平台线程 |
| `std::mutex` / `std::lock_guard` / `std::unique_lock` | `C++11` | 互斥与 RAII 加锁 |
| `std::async` / `std::future` / `std::promise` | `C++11` | 异步任务与结果传递 |
| `std::atomic<T>` | `C++11` | 无锁原子操作 |
| `std::condition_variable` | `C++11` | 线程间等待/通知 |
| `std::shared_mutex`（读写锁） | `C++14` | 多读单写 |
| `std::scoped_lock`（一次锁多个） | `C++17` | 彻底避免死锁的统一加锁 |

```cpp
std::mutex m;
int counter = 0;
std::vector<std::thread> ts;
for (int i = 0; i < 8; ++i)
    ts.emplace_back([&]{
        std::lock_guard<std::mutex> lk(m);   // RAII：构造加锁、析构解锁
        ++counter;
    });
for (auto& t : ts) t.join();
```

> 注意：C++ 标准库的并发模型较底层。Qt 方向课程里更常用 `QThread` + 信号槽的 worker 模式，
> 两者可对照学习——见 `docs/teaching/examples/qthread_worker/`。

---

## 10. 其它实用语言特性

### 10.1 属性 `[[...]]`

| 属性 | 版本 | 作用 |
|---|---|---|
| `[[noreturn]]` | `C++11` | 标注函数永不返回（如 `abort`、死循环） |
| `[[deprecated]]` | `C++14` | 标记弃用，使用时编译警告 |
| `[[deprecated("用 newFunc")]]` | `C++14` | 带提示信息 |
| `[[fallthrough]]` | `C++17` | switch 显式贯穿（抑制警告） |
| `[[nodiscard]]` | `C++17` | 返回值不可忽略（如 `malloc`、工厂函数） |
| `[[maybe_unused]]` | `C++17` | 抑制「未使用」警告 |

```cpp
[[nodiscard]] int* alloc();
auto p = alloc();          // 不接收 → 警告，提醒你检查是否泄漏

switch (n) {
case 1: prepare();
    [[fallthrough]];       // 我是故意贯穿的，别警告
case 2: run();
}
```

### 10.2 `noexcept` `C++11`

```cpp
void swap(T& a, T& b) noexcept;   // 承诺不抛异常
```

**核心概念**：`noexcept` 是函数**接口的一部分**——它让调用者（尤其是 STL 容器）敢于用移动
而非拷贝。移动构造/赋值加 `noexcept` 对性能**至关重要**。`noexcept(expr)` 还能按条件判断：
`void f() noexcept(noexcept(g()));`（f 是否不抛取决于 g）。

> 旧式动态异常规范 `throw(int, char)` 在 C++11 弃用、**C++17 移除**——见
> `docs/VERSION_NOTES.md` 第 6 节与 `tools/demo_versions/dynamic_exception_spec.cpp`。

### 10.3 字符串与字面量 `C++11`

- **`std::to_string` / `std::stoi/stof/stod`**：数值 ↔ 字符串互转。
- **原始字符串字面量** `R"(...)"`：反斜杠、引号都原样保留，写正则/路径/HTML 不再「转义地狱」。
  ```cpp
  std::regex re(R"(\d+\.\d+)");         // 等价 "\\d+\\.\\d+"
  std::string path = R"(C:\Users\me)";  // 反斜杠原样
  ```
- **用户定义字面量 (UDL)**：`"hello"s` 是 `std::string`，`1h`/`1ms` 是 `std::chrono::duration`。
  ```cpp
  using namespace std::string_literals;
  auto s = "hi"s + ", world";           // string + 拼接
  using namespace std::chrono_literals;
  std::this_thread::sleep_for(200ms);
  ```

### 10.4 杂项但常用

| 特性 | 版本 | 备注 |
|---|---|---|
| 范围 for | `C++11` | `for (auto& x : c)` |
| `long long` / `char16_t` / `char32_t` | `C++11` | 标准化的 64 位整型、UTF-16/32 字符 |
| `alignas` / `alignof` | `C++11` | 对齐控制与查询 |
| `thread_local` | `C++11` | 线程局部存储 |
| `using` 别名（取代 `typedef`） | `C++11` | 见 §7.2 |
| 变量模板 | `C++14` | `template<typename T> constexpr T pi = T(3.14159265);` |

---

## 附 A：C++11/14/17 速查表

```
类型推导     auto(11)  decltype(11)  返回auto(14)  decltype(auto)(14)  结构化绑定(17)
移动语义     右值引用(11)  std::move(11)  std::forward(11)  完美转发(11)
资源管理     unique_ptr/shared_ptr/weak_ptr(11)  make_unique(14)  RAII
Lambda       基础(11)  泛型(14)  constexpr(17)
强类型       nullptr(11)  enum class(11)  统一初始化(11)
类增强       =default/=delete(11)  override/final(11)  委托构造(11)  inline变量(17)
模板增强     可变参数(11)  using别名(11)  变量模板(14)  if constexpr(17)  折叠(17)  CTAD(17)
编译期       constexpr(11/14/17)  static_assert(11, 无消息17)
标准库       array/tuple/unordered(11)  emplace(11)  透明比较(14)
             optional/variant/any/string_view/filesystem/并行算法(17)
并发         thread/mutex/future/atomic(11)  shared_mutex(14)  scoped_lock(17)
杂项         范围for/raw string/UDL/noexcept/属性[[...]](11)
```

## 附 B：学习路径建议（给课堂学员）

1. **先建立心智模型**：RAII、移动语义、值类别——这三者理解了，剩下都是语法。
2. **第一周可上手**：`auto`、范围 for、`nullptr`、`enum class`、智能指针、lambda——
   立刻让日常代码更短更安全。
3. **进阶**：完美转发、`constexpr`、模板增强（`if constexpr`/折叠/CTAD）。
4. **C++17 标配库**：`string_view`/`optional`/`variant`/`filesystem` 是日常工程刚需，
   写 Qt 程序时同样适用。
5. **避坑读物**：Scott Meyers《Effective Modern C++》、cppreference.com（查权威细节）。

## 附 C：与本仓库的关联

- **编译基线**：所有示例在 `-std=c++17` 下编译（顶层 `CMakeLists.txt`）。
- **跨版本验证**：想知道某特性在 C++11/14/17 下分别能否编译，用
  `tools/std_probe.py`（例：动态异常规范在 C++17 失败，见 `docs/VERSION_NOTES.md`）。
- **Qt 侧**：本仓库 `p03/` 与 `docs/teaching/examples/` 大量使用了上述现代特性
  （智能指针管理 Qt 对象生命周期、lambda 连信号槽、`QString` 与 `string_view` 互转等）。
- **下一步**：若希望把本文档的某个特性做成可编译运行的 `tools/demo_versions/` 最小示例，
  请明确提出，按项目规范（生成器 / errata 流程）补齐。
