系统性全面的讲解c++20语法,以及列出详细的步骤和分析和包含内容和要点和案例
下午4:07
下面是一份系统性、全面的 C++20 语法与特性的讲解,以“学习路径 + 概念讲解 + 关键要点 + 示例代码 + 实战建议”的形式组织。内容涵盖语言核心、标准库新特性、并发与协程、模块与编译模型、模板与元编程、范围库与迭代器改进、格式化、时间/日历、网络草案现状等。你可以按章节逐步学习与实践。
目录
- 学习路径与环境准备
- 核心语言新增与变化总览
- 模块(Modules)
- 协程(Coroutines)
- 概念(Concepts)与约束(Constraints)
- 范围(Ranges)库
- 三路比较(<=>)与比较语义
- constexpr/consteval 扩展与编译期计算
- 模板与元编程增强(NTTP、类模板实参推导完善等)
- 初始化、聚合、结构化绑定增强与语法小改
- 并发与原子:原子智能指针、原子等待、栅栏等
- 格式化库 std::format
- 日历与时区 <chrono> 扩展
- 容器与迭代器改进
- 文件系统与I/O 增补
- 其他杂项:属性、特性检测、预处理器、标准属性
- 实战:从 C++17 迁移到 C++20 的建议与范式对比
- 练习题与项目建议
————
- 学习路径与环境准备
- 编译器与标准库
- GCC ≥ 11,Clang ≥ 12,MSVC ≥ 19.30(VS 2022)。启用 -std=c++20 或 /std:c++20。
- 模块支持在主流编译器仍有差异,实践时查阅当前版本文档。
- 工具链
- CMake ≥ 3.26 建议;必要时使用编译器专有开关(如 Clang/GCC 的模块实验选项)。
- 学习顺序建议
- 比较运算与语法小改动(低成本收益高)
- format/chrono/ranges 等库(提升日常开发效率)
- concepts/constraints 与三路比较(改善模板与接口设计)
- 协程与并发(根据业务需要)
- 模块(大型工程与编译模型优化)
————
- 核心语言新增与变化总览
- 语言层面
- Concepts 与 requires 表达式
- 三路比较运算符 <=>(宇宙飞船)
- 协程 co_await/co_yield/co_return
- 模块 module/import/export
- constexpr 范围扩大:动态分配、虚函数调用的限制放宽、std::vector 部分 constexpr 化
- consteval 即时函数、constinit 保证静态初始化
- 模板改进:约束友元、模板参数列表中的 requires、NTTP 支持 class 类型字面常量等
- using enum、using 指令改良、结构化绑定到子对象、聚合初始化增强
- lambda 改进:模板形参、默认比较、[=, this] 捕获等
- 标准库
- Ranges 库(视图、投影、管道 |、range adaptor)
- Concepts 库(std::integral、std::floating_point、std::ranges::range 等)
- format(printf 式性能 + typesafe)
- chrono 扩展(calendar/timezone)
- 同步原语:std::barrier、std::latch、原子等待/通知(wait/notify)
- 容器与迭代器特性提升(erase/erase_if、contains、starts_with/ends_with 等)
- constexpr 容器与算法增强
————
- 模块(Modules)
- 目的:替代头文件宏式包含,减少编译时间、避免 ODR/宏污染、获得清晰的接口/实现分离。
- 基本术语
- module interface unit: export 了 API 的单元
- module implementation unit: 实现细节,不导出
- module partition: 模块分区,内部组织
- 最小示例
// math.ixx (接口单元)
export module math;
export int add(int a, int b);
module;
// 这里可以放不导出的全局模块片段的包含(如 #include <vector>)
module math;
int add(int a, int b) { return a + b; }
// main.cpp
import math;
#include <iostream>
int main() {
std::cout << add(2, 3) << '\n';
} - 要点
- 头文件宏不可直接替代为模块;第三方库迁移需要生态支持。
- 编译与链接步骤与传统 .h/.cpp 不同:需要先编译生成 BMI(编译元数据),再链接。
- 仍可与头文件共存,逐步迁移。
————
- 协程(Coroutines)
- 关键词:co_await, co_yield, co_return。通过状态机转换实现惰性/异步流程,不绑定线程。
- 最简生成器示例(同步拉取)
#include <coroutine>
#include <optional>
#include <iostream>
template<typename T>
struct Generator {
struct promise_type {
std::optional<T> value;
Generator get_return_object() { return Generator{std::coroutine_handle<promise_type>::from_promise(*this)}; }
std::suspend_always initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
std::suspend_always yield_value(T v) noexcept { value = std::move(v); return {}; }
void return_void() noexcept {}
void unhandled_exception() { std::terminate(); }
};
std::coroutine_handle<promise_type> h;
~Generator(){ if (h) h.destroy(); }
bool next() { if (!h.done()) h.resume(); return !h.done(); }
T current() const { return *h.promise().value; }
};
Generator<int> counter(int n) {
for (int i = 1; i <= n; ++i) co_yield i;
}
int main() {
auto g = counter(5);
while (g.next()) std::cout << g.current() << " ";
} - 要点
- 标准只提供低层机制;高层异步 I/O 需库支持(如 cppcoro、ASIO)。
- 异步任务类型需自定义 promise_type 语义,设计挂起点策略。
- 与线程不同:协程切换是用户态、无抢占。
————
- 概念(Concepts)与约束(Constraints)
- 用于约束模板形参,提供可读错误与重载选择。
- 示例:排序函数限制为随机访问迭代器
#include <concepts>
#include <ranges>
#include <algorithm>
template<std::random_access_iterator I, std::sentinel_for<I> S>
requires std::sortable<I>
void my_sort(I first, S last) {
std::sort(first, last);
}
int main() {
std::vector<int> v{3,1,2};
my_sort(v.begin(), v.end());
} - 自定义 concept
template<typename T>
concept Addable = requires(T a, T b) {
{ a + b } -> std::same_as<T>;
};
template<Addable T>
T sum(T a, T b) { return a + b; } - requires 子句、requires 表达式、约束重载、约束友元均可用。
————
- 范围(Ranges)库
- 核心理念:基于 range 概念的算法与 views(惰性、可管道)。
- 例子:管道风格处理
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v{1,2,3,4,5,6};
auto rng = v | std::views::filter([](int x){ return x%2==0; })
| std::views::transform([](int x){ return x*x; });
for (int x : rng) std::cout << x << " "; // 4 16 36
} - 常用视图:filter, transform, take, drop, iota, join, split, elements, keys/values
- 算法:std::ranges::sort/find/... 接受 range/迭代器+哨兵,支持投影(projection)
- 要点:惰性、零拷贝;与传统算法互操作;注意借用范围与所有权。
————
- 三路比较 <=> 与比较语义
- 自动生成/自定义强弱序关系,统一 == 与顺序比较。
#include <compare>
struct Point {
int x, y;
auto operator<=>(const Point&) const = default; // 默认成员逐字段比较
};
int main(){
Point a{1,2}, b{1,3};
if (a < b) {} // 基于 <=> 推导
} - 类型:std::strong_ordering / weak / partial(浮点)
- 要点:默认化可减少手写比较器;与容器、排序良好协作。
————
- constexpr/consteval 扩展与编译期计算
- consteval:必须在编译期求值
consteval int pow2(int n) { return 1 << n; }
constexpr int k = pow2(5); // OK
// int r = pow2(5); // 错误:非编译期环境 - constinit:保证静态存储期变量在编译期初始化(防止静态初始化次序问题)
constinit int g = 42; - 更强 constexpr:许多标准库算法与容器支持 constexpr 使用(如 string、vector 在部分实现中)。
————
- 模板与元编程增强
- 非类型模板参数(NTTP)支持类类型字面量(结构体字面类型)
struct Tag { int id; constexpr bool operator==(const Tag&) const = default; };
template<Tag T> struct X {}; - 模板形参包在 lambda 模板中
auto f = []<typename... Ts>(Ts&&... xs) { return (sizeof...(Ts)); }; - requires 在模板形参列表中直接约束
template<typename T> requires std::integral<T>
T add(T a, T b); - using enum 将枚举成员引入当前作用域
enum class Color{ Red, Green, Blue };
void print(Color c){
using enum Color;
if (c == Red) {}
}
————
- 初始化、聚合、结构化绑定等
- 聚合类型规则放宽:有默认成员初值也可聚合;继承与私有成员仍不行。
- 结构化绑定可与 bit-field/匿名 union 子对象配合;可在范围 for 中使用。
- 设计要点:统一使用大括号初始化,减少窄化问题。
————
- 并发与原子
- 原子等待/通知(C++20)
#include <atomic>
#include <thread>
#include <iostream>
int main(){
std::atomic<int> flag{0};
std::thread t([&]{
int expected = 0;
while(!flag.compare_exchange_weak(expected, 1)) expected = 0;
flag.notify_one();
});
flag.wait(0); // 等待值不为 0
std::cout << "proceed\n";
t.join();
} - 同步原语:std::barrier、std::latch 支持一次性/分阶段协调。
- 停止令牌:std::jthread 自动加入 + stop_token 取消。
#include <thread>
#include <stop_token>
#include <chrono>
#include <iostream>
void worker(std::stop_token st){
while(!st.stop_requested()){
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
std::cout << "stopped\n";
}
int main(){
std::jthread th(worker); // 自动 join
std::this_thread::sleep_for(std::chrono::milliseconds(200));
th.request_stop();
}
————
- 格式化库 std::format
- 类型安全、快速、Python 风格。
#include <format>
#include <iostream>
int main(){
std::cout << std::format("Hello {}, pi≈{:.3f}\n", "C++20", 3.14159);
} - 自定义格式化器需特化 std::formatter<T>。
- 注意:某些平台需启用/链接支持库;老 libc++ 版本可能缺失。
————
- <chrono> 日历与时区
- civil calendar:year, month, day, sys_time, local_time, zoned_time
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main(){
year_month_day ymd{2025y, March, 14d};
sys_days sd = ymd;
auto weekday = std::chrono::weekday{sd};
std::cout << int(weekday.c_encoding()) << "\n"; // 0=Sun
} - 时区数据库访问 std::chrono::get_tzdb(); zoned_time 进行本地化转换。
- 格式化与解析:std::format 支持 chrono 类型的格式控制。
————
- 容器与迭代器改进
- 容器便捷:
- map/set: contains
- string: starts_with, ends_with, contains
- erase/erase_if(容器, 谓词) 返回删除数量
- span:非拥有视图
- array 改善 constexpr
- 迭代器分类与 sentinels:ranges 算法能以迭代器+哨兵结束,不要求同型。
示例:erase_if
#include <vector>
#include <algorithm>
#include <iostream>
int main(){
std::vector<int> v{1,2,3,4,5,6};
auto n = std::erase_if(v, [](int x){ return x%2==0; });
std::cout << n << " removed, size=" << v.size() << "\n";
}
————
- 文件系统与 I/O 增补
- <filesystem> 来自 C++17,C++20 修正缺陷,配合 format 与 chrono 使用更佳。
- text_encoding/网络库并未正式进入 C++20;网络 TS 尚未标准化。
————
- 其他杂项
- 标准属性
- [[likely]] / [[unlikely]] 提示分支预测
- [[no_unique_address]] 消除空基类开销
- [[nodiscard("msg")]] 细化原因
- 特性检测宏与特性测试
- __cpp_concepts, __cpp_lib_format, __cpp_coroutines 等,用于条件编译。
- 预处理器与 include 次序
- 与模块混用时,尽量减少全局宏;使用 export import 的清晰边界。
————
- 从 C++17 迁移到 C++20:范式对比与步骤
- 步骤建议
- 启用新标准并开启告警(-Wall -Wextra -Wconversion 等),加入 CI。
- 替换常见工具:
- fmt::format → std::format(或继续用 fmt 同接口)
- 手写算法链 → ranges 管道
- 手写比较器 → operator<=> = default
- enable_if/traits → concepts/requires
- 手写线程 join → std::jthread + stop_token
- 渐进引入:
- 先引入库特性(低风险)
- 再在边缘模块尝试 concepts/ranges
- 最后考虑协程与模块(生态/编译器成熟后)
- 常见坑
- std::format 在旧 libc++/libstdc++ 版本缺失或不完整。
- 协程需要合适的调度与等待器适配;与异常交互策略要明确。
- Ranges 对迭代器/所有权要求更严,临时对象生命周期要注意。
- <=> 对浮点是部分序;容器排序要小心 NaN。
————
- 练习题与小项目
- 概念与 ranges
- 为通用数值类型编写 clamp_range 函数,要求 InputRange 且可投影。
- 协程
- 实现一个简易 async_task,封装 co_await future-like 的接口与调度器。
- 模块
- 将一个中型库分成 module interface + implementation + partitions,测量编译时间变化。
- 格式化与 chrono
- 写一个日志库:std::format + zoned_time + source_location(C++20 有 std::source_location)。
- 三路比较
- 为多个业务实体类型默认化 <=>,验证排序与哈希一致性。
————
附加:综合案例(概念 + ranges + format + <=>)
- 需求:读取一组点,过滤合法点,按距离排序并打印。
#include <vector>
#include <ranges>
#include <cmath>
#include <format>
#include <compare>
#include <iostream>
struct Point {
double x{}, y{};
auto operator<=>(const Point&) const = default;
};
template<typename R>
concept PointRange = std::ranges::input_range<R> &&
std::same_as<std::ranges::range_value_t<R>, Point>;
double dist2(const Point& p){ return p.xp.x + p.yp.y; }
void process(PointRange auto rng) {
auto filtered = rng
| std::views::filter([](const Point& p){ return std::isfinite(p.x) && std::isfinite(p.y); })
| std::views::transform([](Point p){ return p; }); // 可插入投影
std::vector<Point> buf(filtered.begin(), filtered.end());
std::ranges::sort(buf, {}, &dist2); // 按距离平方排序(投影)
for (auto& p : buf)
std::cout << std::format("({:.2f}, {:.2f}) d2={:.2f}\n", p.x, p.y, dist2(p));
}
int main(){
std::vector<Point> pts{{3,4},{1,2},{-1,5}};
process(pts);
}
———
结语
这份提纲覆盖 C++20 的主要语法与标准库特性,并提供了要点与示例。若你有特定领域(网络/高并发/游戏/嵌入式/金融)应用场景,我可以基于此给出更聚焦的最佳实践与代码模板,并提供分阶段的学习计划与检查清单。

5万+

被折叠的 条评论
为什么被折叠?



