# C++20 与以后（C++20 / 23 / 26 概览）

> 本文是 [`MODERN_CPP.md`](MODERN_CPP.md)（C++11/14/17）的续篇。
>
> **范围与基线说明**：本仓库的编译基线仍是 **C++17**（见顶层 `CMakeLists.txt`），所以本文介绍的是 **C++20 起** 的「进阶/前瞻」特性——需要在 `-std=c++20` / `-std=c++23` 下编译，**不**是本仓库示例默认能用的版本。每节标注引入版本；附录给出本机 **GCC 13.3.0** 的实测可用性（不是猜的，每条都编过）。
>
> 为什么单列一份：C++20 是继 C++11 之后**最大**的一次语言更新，四大件（Concepts / Ranges / Coroutines / Modules）体量足够撑一份独立文档。

---

## 0. 版本脉络：C++20 是又一次「大爆炸」

| 版本 | 年份 | 定位 | 标志性内容 |
|---|---|---|---|
| C++17 | 2017 | 实用增量 | `optional`/`variant`/`string_view`/`filesystem`/结构化绑定 |
| **C++20** | 2020 | **四大件** | Concepts · Ranges · Coroutines · Modules ＋ `<=>` · `std::format` |
| **C++23** | 2023 | 完善与补库 | `expected` · `std::print` · `mdspan` · `flat_map` · ranges 扩展 · 推导 `this` |
| C++26 | 2026（开发中） | 暂定 | `std::execution`(Senders/Receivers) · `=delete("...")` · `inplace_vector` · 契约/反射（未定） |

Stroustrup 评价 C++20：「自 C++11 以来对 C++ 最大的冲击。」

**四大件一句话**：
1. **Concepts（概念）**——给模板加约束，错误信息从「天书」变「人话」。
2. **Ranges（范围）**——可组合、惰性的区间管道，STL 算法的现代化。
3. **Coroutines（协程）**——语言级协程，生成器/异步的统一底座。
4. **Modules（模块）**——替代 `#include`，更快编译 + 更干净的封装。

> **关于工具链**：本文附录 A 给出了**本机 GCC 13.3.0 的实测矩阵**。结论先行：
> **C++20 几乎全可用**；**C++23 的语言特性多数可用，但不少库（`<print>`/`<mdspan>`/`<flat_map>` 等）要 GCC 14+**；**C++26 在 13.3 上基本用不了**（需 GCC 14+ 且开 `-std=c++2c`）。课堂演示时请按此选用。

---

## 1. Concepts：给模板加约束 `C++20`

### 1.1 问题：模板错误信息「天书」

一个没有约束的模板，对所有类型都「假装能用」，直到实例化时在**最深处**失败：

```cpp
template<typename T>
void print(const T& x) { std::cout << x; }   // 要求 x 可 <<

struct Foo {};
print(Foo{});   // ❌ 报错：operator<< 找不到，外加一长串模板展开
```

编译器把 `operator<<` 失败的整条实例化链路倒给你看，真正有用的「`Foo` 根本不可流式输出」
被淹没在几十行噪声里。Concepts 的目标：**在实例化前就用一句人话告诉你类型不达标**。

### 1.2 三个能力合在一起：命名谓词 + `requires` 表达式 + 能力分派

下面是一个**能体现 Concepts 全部威力**的例子——一个「按类型能力分派」的通用 `print`：
`int`/`std::string` 直接打印，容器（如 `vector`）递归逐元素打印，二者靠**类型能力**自动选对。

```cpp
#include <concepts>
#include <iostream>
#include <vector>
#include <string>

// 概念 1：可流式输出——探查一个 operator<<，并要求返回类型是 ostream&
template<typename T>
concept Printable = requires(std::ostream& os, const T& t) {
    { os << t } -> std::same_as<std::ostream&>;
};

// 概念 2：可迭代——探查成员函数 begin()/end()
template<typename T>
concept Iterable = requires(const T& t) {
    t.begin();
    t.end();
};

// 重载 A：可流式的直接打印（int / std::string / const char* ……）
void print(const Printable auto& x) {
    std::cout << x;
}

// 重载 B：可迭代、但本身不能直接 << 的容器 → 递归逐元素打印
template<typename T>
requires Iterable<T> && (!Printable<T>)
void print(const T& c) {
    std::cout << "[ ";
    for (const auto& e : c) print(e);   // 递归：容器套容器也能打
    std::cout << "] ";
}

int main() {
    print(42);                                  // → A
    print(std::string("s"));                     // → A（string 能 <<，不进 B）
    print(std::vector<int>{1, 2, 3});            // → B
    print(std::vector<std::vector<int>>{{1,2},{3,4}});  // → B 递归到 B 再到 A
    // print(Foo{});   // ❌ 编译错误：清晰，见下
}
```

运行输出：
```
42
s
[ 1 2 3 ]
[ [ 1 2 ] [ 3 4 ] ]
```

这个小例子同时展示了 Concepts 的**四个关键能力**（这正是 `add(Number)` 那种玩具例子看不到的）：

| 能力 | 体现在 |
|---|---|
| **`requires` 表达式探查成员** | `Iterable` 用 `t.begin(); t.end();` 检查成员函数是否存在 |
| **探查运算符 + 返回类型要求** | `Printable` 用 `{ os << t } -> std::same_as<std::ostream&>;` |
| **能力分派（按类型能力重载）** | 两个 `print` 重载靠 `Printable` / `Iterable` 自动二选一 |
| **概念可参与逻辑运算** | `requires Iterable<T> && (!Printable<T>)` 用 `!` 排除已处理情况 |

> **那个 `!Printable<T>` 是关键细节**：`std::string` 同时满足 `Printable` 和 `Iterable`
> （它既能 `<<` 又有 `begin/end`）。若不加 `!Printable<T>`，两个重载都可行且互不约束
> → 调用歧义报错。这里要求重载 B 只处理「可迭代但不可流式」的类型，让 `std::string`
> 干净地落进重载 A。这是实际工程里反复用到的模式。

### 1.3 报错终于说人话了

把上面 `print(Foo{})` 的注释去掉，错误信息变成：

```
required for the satisfaction of 'Printable<auto:16>' [with auto:16 = Foo]
note: constraints not satisfied
```

一句话点出「`Foo` 不满足 `Printable`」，不再有模板展开噪声。

### 1.4 挂载概念的三种写法（用最小的例子演示语法）

上例用了**简写模板语法** `void print(const Printable auto& x)`，最清爽。完整三种写法：

```cpp
template<typename T>
concept Number = std::integral<T> || std::floating_point<T>;   // 组合标准库概念

// ① requires 子句（前置）
template<typename T> requires Number<T>
T add1(T a, T b) { return a + b; }

// ② requires 子句（尾随，适合约束长时）
template<typename T>
T add2(T a, T b) requires Number<T> { return a + b; }

// ③ 简写模板语法（推荐，省掉 typename）
auto add3(Number auto a, Number auto b) { return a + b; }
```

`requires(...) { 表达式序列 }` 检查这些表达式**是否合法**，还能用 `-> 概念` 附加返回类型要求，
概念本身可由 `&&` `||` `!` 组合（如上例），也可由标准库概念（`<concepts>` 里的 `integral`、
`floating_point`、`same_as`、`convertible_to`、`derived_from`…）拼装。

**常见的坑**：
- **能力重叠 → 歧义**：一个类型同时满足多个概念、且无一个更「强」（subsumption）时，
  多个重载都可行 → 编译歧义。上面用 `!Printable<T>` 显式排除就是解法之一。
- **约束太松仍会回到「天书」**：概念只写 `template<typename T>` 不加 `requires`，
  失败照样从深处爆出来——概念的价值在于**把约束前置、命名**。
- **concept 是零开销**：纯编译期谓词，不参与运行期、不产生代码。

---

## 2. Ranges：可组合的区间管道 `C++20`

```cpp
#include <ranges>
#include <vector>
#include <algorithm>
#include <iostream>

int main() {
    namespace rv = std::views;

    // 管道：惰性求值，不产生中间容器
    auto result = std::views::iota(1)              // 1, 2, 3, ...
                | rv::filter([](int x){ return x % 2 == 0; })  // 偶数
                | rv::transform([](int x){ return x * x; })    // 平方
                | rv::take(5);                     // 取前 5 个 → 4,16,36,64,100

    for (int x : result) std::cout << x << " ";
}
```

**核心概念**：
- **视图 (view)**：轻量、**惰性**的区间适配器（如 `filter`/`transform`/`take`/`drop`）。不拷贝数据，遍历时才计算，可 O(1) 拷贝。
- **管道 `|`**：像 Unix 管道一样把多个适配器串起来，`a | f | g`。
- **ranges 算法**：`std::ranges::sort(v)` / `std::ranges::find(v, x)` 直接吃容器，不用 `v.begin()/v.end()`；还支持投影 `sort(people, {}, &Person::age)`。
- **C++23 扩展**：`views::enumerate`（带下标遍历）、`views::zip`（并行拉链）、`views::slide`/`chunk`/`stride`/`adjacent` 等（见附录 A 可用性）。

**常见的坑**：
- 视图是**惰性**的：`filter` 里的谓词在遍历时才执行，定义时不跑。
- 视图**不拥有**底层容器：容器销毁后视图悬垂（类似 `string_view`）。
- `iota(1)`（无上界）是无限区间，必须配合 `take` 之类才有穷，否则 `for` 死循环。

---

## 3. Coroutines：语言级协程 `C++20`

协程是能**暂停、再恢复**的函数，用三个关键字：`co_await`（等待异步操作）、`co_yield`（产出一个值）、`co_return`（结束）。

```cpp
#include <coroutine>
#include <iostream>

// 最小生成器（C++20 没有标准 std::generator，需自己写 promise_type；
//   C++23 才有 <generator> 直接可用，见附录 A）
Generator<int> count_up(int from) {
    while (true)
        co_yield from++;        // 每次调用 next() 唤醒，产出一个数
}

int main() {
    auto g = count_up(10);
    for (int i = 0; i < 3; ++i)
        std::cout << g() << " ";   // 10 11 12
}
```

**核心概念**：
- 函数体里出现 `co_await`/`co_yield`/`co_return` 之一，即为协程。
- 协程**返回一个「协程句柄对象」**（其类型必须含 `promise_type`），调用者通过它控制暂停/恢复。
- 框架只规定**机制**（如何挂起/恢复、如何把值传出去），**策略**（调度、I/O）由库或你自己的 `promise_type` 实现。所以**裸 C++20 协程偏底层**，实际多用库（CppCoro/ASIO/C++23 的 `std::generator`）。

**常见的坑**：
- 协程帧在堆上分配，生命周期与返回的句柄绑定——句柄销毁前协程不能跑完 → 泄漏/悬垂。
- 协程本身的「调度」要你自己接，标准库不提供线程池或事件循环（C++26 的 `std::execution` 在补这块，暂定）。

> Qt 侧：Qt 也有协程支持（Qt Coroutine / 协程化的信号槽），但课程内异步更常用 `QThread` + 信号槽，协程属进阶内容。

---

## 4. Modules：替代 `#include` `C++20`

```cpp
// ---- greet.cppm（模块接口单元）----
export module greet;
export int hello() { return 42; }

// ---- main.cpp----
import greet;
int main() { return hello(); }
```

**核心概念**：模块是**语义导入**——编译一次后缓存为二进制接口（`.gcm` 等），下游导入不重复解析，也不受宏污染。相比 `#include` 的「文本粘贴」，模块带来：
- **更快编译**（无重复解析、无宏展开风暴、头文件顺序无关）。
- **更好封装**（`export` 才对外可见，内部实现不泄漏符号/宏）。

**重要的现实情况**（务必在课堂上讲清）：
- 模块的**语言机制**已在 C++20 定稿，但**构建系统集成（CMake/Make/Ninja）与各编译器（GCC/Clang/MSVC）的支持在 C++20 周期是「能用但繁琐」**：GCC 要 `-fmodules-ts` 并安排模块的预编译顺序、生成 `.gcm` 缓存；CMake 到 3.28+ 才较好地支持。
- `import std;`（直接导入整个标准库）要**更晚**的工具链（GCC 14+ / Clang 17+ / MSVC 19.36+）才好用。
- 本机 GCC 13.3 可以编模块，但需要手动编排编译顺序（详见附录 A 的实测说明）。
- **结论**：课堂以「讲机制 + 看语法」为主；要做成可运行示例，需投入构建脚本，超出本仓库「最小示例」范畴。

---

## 5. 三向比较 `<=>` `C++20`

```cpp
#include <compare>
struct Point {
    int x, y;
    auto operator<=>(const Point&) const = default;   // 一行生成 <,<=,==,!=,>=,>
};
```

**核心概念**：`<=>`（"宇宙飞船运算符"）做**三向比较**，返回一个**比较类别**：
- `std::strong_ordering`（`less`/`equal`/`greater`，全序，如 `int`）
- `std::weak_ordering`（相等但不等价，如大小写不敏感的字符串）
- `std::partial_ordering`（可能无序，如浮点 `NaN`）

`= default` 让编译器按成员逐一比较，自动派生全部 6 个关系运算符。也可以**只 `=default` `==`**，编译器会反过来补 `!=`。

```cpp
struct V {
    int x;
    bool operator==(const V&) const = default;   // 自动获得 !=
};
```

**常见的坑**：
- `double` 之间是 `partial_ordering`（因为有 `NaN`），`a <=> b` 的结果可能是 `unordered`。
- `operator<=>` 默认生成 `==`/`!=`；但若类含指针或不希望全序，需自己定义。

---

## 6. `consteval` 与 `constinit` `C++20`

```cpp
consteval int sq(int x) { return x * x; }   // 立即函数：必须在编译期求值
constinit int g = sq(5);                     // 常量初始化（值可在运行期，但初始化在编译期）

int n;
std::cin >> n;
int a = sq(5);        // OK，编译期
// int b = sq(n);     // ❌ n 不是常量，consteval 强制编译期 → 报错
```

**区别**（三者别混）：

| | `constexpr` | `consteval` | `constinit` |
|---|---|---|---|
| 修饰对象 | 变量 / 函数 | 仅函数 | 仅变量（静态/线程局部） |
| 编译期求值 | **可能**（能在编译期就在，不能就运行期） | **必须**（一定是编译期，否则编译错误） | 初始化**必须**是常量表达式 |
| 是否 `const` | 是 | （函数） | **不是**（值之后可改，只是初始化在编译期） |

**`constinit` 解决什么**：防止**静态初始化顺序灾难**（跨翻译单元的全局对象初始化顺序未定义）。要求初始化是常量表达式，就把对象放进「零开销」的常量初始化阶段，绕开顺序问题。

---

## 7. 更多 `constexpr`：编译期能做更多 `C++20`

C++20 把 `constexpr` 的边界大幅推开：

- **`constexpr` 动态内存分配**：`constexpr std::vector`、`constexpr std::string`（在常量表达式求值期间分配的内存需在求值结束前释放）。
- **`constexpr` 函数里可用 `try/catch`、`std::is_constant_evaluated()`**（C++20，C++23 升级为 `if consteval`）。
- 大量标准库函数（`<cmath>`、`<algorithm>` 的部分）标记为 `constexpr`。

```cpp
constexpr int build_sum() {
    std::vector<int> v{1, 2, 3, 4};     // C++20：constexpr vector
    int s = 0;
    for (int x : v) s += x;
    return s;                            // 析构时释放，编译期合规
}
static_assert(build_sum() == 10);
```

---

## 8. Lambda 与函数对象增强

### 8.1 模板 lambda `C++20`

```cpp
auto f = []<typename T>(std::vector<T> const& v) {
    return v.size();
};
```

让 lambda 像模板一样把类型当参数，**不需要再用 `auto` 模糊推导**——能在参数列表精确写出 `std::vector<T> const&`。

### 8.2 推导 `this`（显式对象参数）`C++23`

```cpp
struct Builder {
    // self 是显式的「this 参数」，类型可推导 → lambda 能递归、能写 CRTP 式重载
    void log(this auto& self, std::string_view msg) { /* ... */ }
};

// 递归 lambda（以前只能用 std::function 或 Y 组合子）：
auto fib = [](this auto& self, int n) -> int {
    return n < 2 ? n : self(n - 1) + self(n - 2);
};
```

**核心概念**：把 `this` 写成**显式参数**（`this auto& self`），类型可推导。一举多得：递归 lambda、const/非 const 重载统一、消除 CRTP 样板。

> 本机 GCC 13.3 **不支持**推导 `this`（附录 A），演示需 GCC 14+。

### 8.3 多维 `operator[]` 与静态 `operator()` `C++23`

```cpp
struct Matrix {
    double operator[](int i, int j) { return data[i * cols + j]; }   // 多维下标
    int data[100], cols;
};
struct Less { static bool operator()(int a, int b) { return a < b; } }; // 静态调用
```

---

## 9. 杂项但常用的语言特性 `C++20/23`

| 特性 | 版本 | 示例 |
|---|---|---|
| 指定初始化 | `C++20` | `Point p{.x = 1, .y = 2};`（来自 C，受限形式：须按声明顺序、不嵌套） |
| 范围 for 的初始化语句 | `C++20` | `for (auto& c = get(); auto& e : c) { ... }` |
| `char8_t` | `C++20` | `u8""` 的类型从 `char` 变成独立的 `char8_t`（**ABI 破坏**，老代码要改） |
| `using enum` | `C++20` | `using enum Color;` 把枚举值引入作用域 |
| 聚合体 CTAD | `C++17/20` | `std::array a{1,2,3};` 推导 `array<int,3>` |
| `if consteval` | `C++23` | 替代 `std::is_constant_evaluated()`，更清晰 |
| `=delete("原因")` | `C++26` | 删函数时带诊断信息（本机 `-std=c++2b` 已可编译） |
| 位域成员默认初始化 | `C++20` | `struct { unsigned a : 3 = 0; };` |

---

## 10. 标准库大件 `C++20`

### 10.1 `std::format`：Python 风格格式化 `C++20`

```cpp
#include <format>
std::string s = std::format("x = {}, pi ≈ {:.3f}", 42, 3.14159);
```

替代 `printf`（不类型安全）和 `iostream`（冗长、慢）的中间路线：`{}` 占位 + 安全的类型检查。
> **C++23** 的 `std::print`/`std::println` 让你直接 `std::println("x = {}", 42)`，连 `std::format`+`<<` 都省了（本机要 GCC 14+）。

### 10.2 `<chrono>` 日历与时区 `C++20`

```cpp
using namespace std::chrono;
auto year = 2025y;
auto date = 2025y/January/1d;          // 年/月/日：日历字段（字面量 y / Month / d）
auto next_week = sys_days{date} + weeks{1};   // 日期 + 时长
auto dur = days{7} + 12h + 30min;     // 时长：180 小时（注意 days 是复数 = duration）
```

把日历（年月日、星期）、时长、时区都纳入类型系统，编译器帮你抓「天数+小时数」这类单位错误。

**坑（极易踩）**：`7d`（单数字面量）是 `chrono::day` **日历字段**（一个月里的「几号」），
**不是**「7 天的时长」。7 天的时长要写 `days{7}`（复数类型 = duration）或 `7*24h`。
所以 `7d + 12h` **不能编译**——字段不能和时长相加；只有 `sys_days{date} + weeks{1}`
这种「日期点 + 时长」才行。

### 10.3 `std::span`：连续内存的非拥有视图 `C++20`

```cpp
void process(std::span<int> data);    // 接收数组 / vector / 某段 —— 零拷贝、带长度
int arr[4];  std::vector<int> v;
process(arr);  process(v);  process(std::span{v}.subspan(2, 5));
```

C++ 版的「指针+长度」：栈数组、`vector`、`array` 都能无开销绑定，函数签名终于不必在 `T*` 与 `vector<T>&` 之间二选一。

### 10.4 `std::jthread`：可停止的线程 `C++20`

```cpp
#include <thread>
std::jthread worker([](std::stop_token st){
    while (!st.stop_requested()) { /* ...干活... */ }
});
// worker 析构时自动 join，且可 worker.request_stop() 协作式取消
```

比 `std::thread` 多两点：**析构自动 `join`**（不会 `std::terminate`）、内置**协作式取消**（`stop_token`）。

### 10.5 其它 `C++20` 库

| 头文件 | 用途 |
|---|---|
| `<bit>` | `std::bit_cast`（类型双关，替代 `memcpy` 把戏）、`popcount`、`countl_zero`、`rotr`、`bit_ceil` |
| `<numbers>` | `std::numbers::pi`、`e`、`sqrt2`…（变量模板） |
| `<source_location>` | `std::source_location::current()` 取当前文件/行/函数（替代 `__FILE__`/`__LINE__` 宏） |
| `<version>` | 标准库特性检测宏 |
| `<concepts>` | 标准概念库：`integral`/`floating_point`/`same_as`/`convertible_to`… |
| `<ranges>` | 范围与视图 |
| `<coroutine>` | 协程底层设施 |

---

## 11. C++23 速览

C++23 主要是**补 C++20 的坑 + 加库**：

| 类别 | 特性 | 一句话 |
|---|---|---|
| 错误处理 | `std::expected<T,E>` | 类型化的「成功/失败」，替代异常或返回码 |
| 输出 | `std::print` / `std::println` | `std::format` 直接打印到流 |
| 多维 | `std::mdspan` | 多维数组的非拥有视图（GPU/HPC 常用） |
| 容器 | `std::flat_map` / `flat_set` | 有序但连续存储的「扁平」关联容器（缓存友好） |
| 调试 | `std::stacktrace` | 运行期取调用栈 |
| optional 单子 | `and_then` / `or_else` / `transform` | 链式处理「可能无值」 |
| 工具 | `std::to_underlying` / `std::unreachable` / `std::byteswap` | 枚举转整数 / 标记不可达 / 字节反转 |
| 范围 | `views::enumerate` / `zip` / `slide` / `chunk` / `adjacent` / `stride` | 区间管道再扩 |
| 语言 | 推导 `this` / `if consteval` / 多维 `[]` / 静态 `operator()` | 见 §8 |

```cpp
// expected：替代异常的「带类型的错误」
std::expected<int, std::string> parse(std::string_view s) {
    if (s.empty()) return std::unexpected("empty");
    return 42;
}
if (auto r = parse("x")) use(*r); else handle(r.error());

// views::enumerate：带下标遍历，告别手动 i++
for (auto [i, v] : std::views::enumerate(items)) { /* ... */ }
```

---

## 12. C++26 展望（暂定，未完全定稿）

> **状态声明**：C++26 标准还在制定中，以下为「候选/已合并」特性，**本机 GCC 13.3 基本都还用不了**（需 GCC 14+，多数需 `-std=c++2c`，本机连该标志都不识别）。列在这里是为了让学员建立「C++ 还在持续演进」的认知。

- **`std::execution`（Senders/Receivers，P2300）**：标准化的异步/并行执行框架，C++ 终于有统一的「调度 + 组合异步操作」底座。
- **`= delete("原因")`**：删函数带诊断信息（本机 `-std=c++2b` 已能编译，是少数现在能试的）。
- **`std::inplace_vector`**：栈上、容量固定的 `vector`（不动态分配，适合嵌入式/实时）。
- **`std::linalg`**：基于 `mdspan` 的线性代数（BLAS 风格）。
- **`#embed`**：把二进制文件直接嵌入源码，替代 `xxd`/工具链把戏。
- **打包下标 `a[1, 2, 3]`**：一次取多个元素。
- **契约（Contracts）/ 静态反射（Reflection）**：呼声很高，但能否进 C++26 仍有变数（多次反复）。

---

## 附 A：本机 GCC 13.3.0 实测可用性矩阵

> 全部为 `-std=c++20` / `-std=c++23` / `-std=c++2b` 下的**实测**结果（`-Wall -pedantic-errors`）。✅ 可用 / ❌ 缺失或需更高版本。

### C++20（基本全可用）

| 特性 | 结果 | 备注 |
|---|---|---|
| Concepts（`requires` / 简写 / `<concepts>`） | ✅ | |
| Ranges（`views::`、`ranges::sort`、管道） | ✅ | |
| `<=>` / `<compare>` | ✅ | |
| `consteval` / `constinit` | ✅ | |
| `std::format` / `<format>` | ✅ | |
| `std::span` / `<bit>` / `<numbers>` / `<source_location>` | ✅ | |
| `std::jthread` + `stop_token` | ✅ | |
| 指定初始化 / 范围 for 初始化语句 / `char8_t` / `using enum` | ✅ | |
| 模板 lambda `[]<typename T>(...)` | ✅ | |
| `<chrono>` 日历字面量 | ✅ | |
| **Modules** | ⚠️ | 语言机制可用，但需手动编排编译顺序与 `.gcm` 缓存，构建系统集成在 CMake 3.28+ 才较好 |
| Coroutines（`<coroutine>`） | ⚠️ | 机制可用，但 `std::generator` 要 C++23，C++20 需自写 `promise_type` |

### C++23（语言特性多数可用，库分两半）

| 特性 | 结果 | 备注 |
|---|---|---|
| `if consteval` | ✅ | |
| 多维 `operator[]`（`a[i,j]`） | ✅ | |
| 静态 `operator()` | ✅ | |
| `std::to_underlying` / `std::unreachable` / `std::byteswap` | ✅ | |
| `<expected>` | ✅ | |
| `std::optional` 单子（`and_then`/`transform`/`or_else`） | ✅ | |
| `views::enumerate` / `zip` / `slide` | ✅ | |
| **推导 `this`**（`this auto& self`） | ❌ | 需 GCC 14+ |
| **`<print>` / `std::println`** | ❌ | 需 GCC 14+ |
| **容器 `std::format`**（`format("{}", vector)`） | ❌ | 需 GCC 14+ |
| **`<mdspan>` / `<flat_map>` / `<inplace_vector>`** | ❌ | 需 GCC 14+ |
| **`<stacktrace>`** | ⚠️ | 头文件存在，但需链接 `-lstdc++_exp`，本机**无该库** → 实际不可用 |
| **`std::generator`** | ❌ | 需 GCC 14+ |

### C++26（本机基本不可用）

| 特性 | 结果 | 备注 |
|---|---|---|
| `-std=c++2c` / `-std=c++26` 标志 | ❌ | 本机 GCC 13.3 不识别该标志 |
| `= delete("原因")` | ✅ | `-std=c++2b` 下可编译（少数能试的） |
| `std::execution` / `inplace_vector` / `#embed` / 契约 / 反射 | ❌ | 全部需 GCC 14+，多数尚未实现 |

---

## 附 B：学习路径建议

1. **先吃透 C++17**（见 [`MODERN_CPP.md`](MODERN_CPP.md)）：移动、智能指针、lambda、`optional`/`variant` 是 C++20 的前提。
2. **C++20 入门顺序**：Concepts → Ranges → `<=>` → `std::format`/`span`/`jthread`；Modules 和 Coroutines 放最后（构建/调度复杂度高）。
3. **C++23 实用件**（你的工具链够新时）：`expected`、`std::print`、`views::enumerate`——日常工程立刻能受益。
4. **C++26** 持续关注，不必急着用——标准与实现都还在收敛。
5. **权威参考**：[cppreference.com](https://en.cppreference.com/w/)、[C++ 标准委员会邮件列表](https://www.open-std.org/jtc1/sc22/wg21/)、Sutter《Welcome to the Jungle / 历年 trip report》。

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

- **本仓库基线 C++17**：本文件所有特性都**超出基线**，需显式开 `-std=c++20`+；仓库默认构建（`cmake -DCMAKE_BUILD_TYPE=Debug`）不会触及。
- **如需在课堂上跑 C++20 演示**：可在 `tools/demo_versions/` 加一个 `-std=c++20` 的目标（需在生成器/CMake 里单独加 `COMPILE_OPTIONS`），与现有 `std_probe.py` 跨版本对比机制衔接。**这属于新增工程改动，需要你明确指令我才执行。**
- **跨版本探针**：`tools/std_probe.py` 已支持把片段喂给任意 `-std=`，可用它复现本文附录 A 的矩阵。
- **Qt 侧**：Qt 6 对 C++17 是基线、对 C++20 部分采用；本仓库用的隔离 Qt 5.14.2 以 C++17 为准，C++20 特性暂不混入 `p03/` 生成产物。
