跳转至

校准基础认知

建立 C++11、C++14、C++17、C++20 的整体版本地图,先把边界理清。

目标:看到一个特性时,先能判断它属于哪个标准、解决哪类问题、在整体演进里处于哪一层,以及它主要在替代什么旧写法,而不是把 11、14、17、20 混成一团。

1 版本定位

  • C++11:现代 C++ 起点
    建立类型推导、值语义、lambda、并发等现代基础设施。

  • C++14:对 C++11 的补强
    让推导、泛型和 constexpr 更自然。

  • C++17:工程实用性明显增强
    模板分支、值封装、视图类、文件系统进一步成熟。

  • C++20:语言与库继续体系化
    概念约束、ranges、协程、同步原语继续完善。

2 基础语法与对象模型

解决:旧式基础写法不够安全、不够清晰,资源转移与对象语义表达不足。

  • 右值引用 / move 语义 —— C++11
    替代:不必要拷贝、资源转移成本高

  • nullptr —— C++11
    替代:NULL / 0 造成的空指针歧义

  • range-based for —— C++11
    替代:手写迭代器循环

  • enum class —— C++11
    替代:传统枚举污染作用域、隐式转换过多

  • override / final —— C++11
    替代:虚函数覆写靠人工检查,容易签名写错

  • =default / =delete —— C++11
    替代:特殊成员函数行为表达不直接、禁止接口不明确

  • 委托构造 / 继承构造 —— C++11
    替代:构造逻辑重复、派生类构造转发啰嗦

  • 统一初始化 —— C++11
    替代:多套初始化语法并存、风格不统一

  • noexcept —— C++11
    替代:异常规格写法弱且语义不清

C++11:把很多“旧 C++ 基础写法”整体换代
这一层不是炫技特性,而是现代 C++ 代码风格的底板

3 类型推导与泛型

解决:类型书写冗长、泛型表达能力不足、模板约束不清晰。

  • auto —— C++11
    替代:显式长类型声明

  • decltype —— C++11
    替代:模板上下文中手写复杂类型

  • using —— C++11
    替代:typedef,尤其是模板别名场景下更自然

  • decltype(auto) —— C++14
    替代:返回类型保真不足,容易丢引用 / cv 属性

  • 泛型 lambda —— C++14
    替代:手写仿函数、单独写模板函数对象

  • lambda init-capture —— C++14
    替代:lambda 对 move-only 对象或初始化式捕获支持不足

  • 类模板实参推导(CTAD)—— C++17
    替代:显式写类模板参数

  • structured bindings —— C++17
    替代:pair / tuple 返回值只能通过 first / second / get<> 拆解

  • concepts / requires —— C++20
    替代:无约束模板、SFINAE、enable_if

C++11:开始“少写类型”,别名与接口表达更自然
C++14:让推导和泛型 lambda 更顺手
C++17:连模板实参和返回值拆解都开始简化
C++20:从“能写泛型”升级到“能约束泛型”

4 编译期能力与条件分发

解决:哪些逻辑能放到编译期、模板代码如何按条件分发、初始化约束如何表达。

  • constexpr —— C++11
    替代:只能做很弱的编译期计算

  • static_assert —— C++11
    替代:模板错误只能在深层报出、约束与假设难以前置表达

  • 增强版 constexpr —— C++14
    替代:早期 constexpr 可写性太弱

  • if constexpr —— C++17
    替代:普通 if + 模板特化绕行、SFINAE 分发

  • fold expressions —— C++17
    替代:参数包递归展开、模板样板代码

  • consteval / constinit —— C++20
    替代:编译期求值要求不明确、静态初始化约束表达不清

C++11:constexpr 起步,但能力偏弱
C++14:constexpr 可写性增强
C++17:if constexpr 和 fold expressions 让模板代码更可读
C++20:进一步区分“必须编译期求值”和“静态初始化约束”

5 值语义与类型封装

解决:资源所有权、可空值表达、多类型封装、任意值承载、连续内存视图表达。

  • 智能指针 —— C++11
    替代:裸 new / delete、手工生命周期管理

  • std::optional —— C++17
    替代:特殊值、bool + out 参数、部分值对象缺失场景下用空指针表达失败

  • std::variant —— C++17
    替代:union + 手工维护活跃成员、部分基类指针 + dynamic_cast 分发

  • std::any —— C++17
    替代:void* + 手工转型、弱约束通用承载

C++11:先解决资源管理标准化
C++17:补齐值封装工具
C++20:补齐连续内存的轻量视图表达

6 视图与范围表达

解决:拥有对象与非拥有视图分离,接口从“传具体容器”走向“传视图 / 传范围”。

  • std::string —— 基础能力
    表示拥有数据的字符串对象

  • std::string_view —— C++17
    替代:const std::string& 到处传、const char* / std::string 混杂接口

  • std::span —— C++20
    替代:T* + size、多套数组 / vector / array 接口

  • ranges —— C++20
    替代:迭代器对 + 算法拼装分散、表达链路不直观

C++17:开始把“拥有数据”和“只读视图”分开表达
C++20:进一步把“数据范围”抽象出来,接口与算法表达更统一

7 工程与通用表达

解决:路径/文件操作标准化、格式化输出标准化、调用点信息标准化,以及部分通用表达能力的补齐。

  • std::filesystem —— C++17
    替代:平台相关文件 API、手工拼路径字符串

  • inline variables —— C++17
    替代:头文件中某些静态常量 / 模板静态成员定义不自然

  • std::format —— C++20
    替代:sprintf / snprintf、字符串拼接 + 流式输出混用

  • std::source_location —— C++20
    替代:手工传 __FILE__ / __LINE__ / __func__

  • 三路比较 <=> —— C++20
    替代:成组手写比较运算符

  • designated initializers —— C++20
    替代:聚合初始化时位置依赖强、可读性差

  • modules —— C++20
    替代:头文件包含模型、编译依赖重、宏污染扩散

C++17:filesystem 进入标准库,工程能力明显增强
C++20:格式化、定位、比较、初始化、模块化表达继续补齐

8 并发与异步演进

解决:线程与互斥基础设施、多锁管理、线程协作同步、异步流程表达。

  • std::thread、mutex、lock_guard —— C++11
    替代:平台私有线程接口、手工 lock / unlock

  • std::unique_lock、condition_variable —— C++11
    替代:更弱的锁控制方式、手工轮询 / 低层线程等待协调

  • future / promise / async —— C++11
    替代:线程结果回传靠共享变量、手工协议传递异步结果

  • std::atomic —— C++11
    替代:部分轻量同步场景下完全依赖 mutex

  • std::scoped_lock —— C++17
    替代:多个锁手工管理顺序

  • latch、barrier、semaphore —— C++20
    替代:自旋、手工计数协议、弱抽象同步控制

  • jthread / stop_token —— C++20
    替代:线程生命周期更难管理、缺乏统一取消语义

  • coroutines —— C++20
    替代:回调链、手写状态机、拆碎的异步流程

C++11:并发基础设施进入标准库
C++17:锁管理进一步简化
C++20:同步原语更完整,线程取消语义开始标准化,协程进入语言层