上一篇我们搞定了 CMake 构建。但在写代码之前,还有一个「地图」问题:C++ 到底演进了哪些版本?每个版本加了什么? 如果你还在用 C++98 的思维读 C++20 的代码,很容易觉得「语法怎么又变了」。

这一篇不深入任何单一特性,而是把 C++03 → C++26 的演进脉络梳理清楚,并带你跑一遍 version_features demo——后面 25 篇特性文章,都可以在这张地图上找到位置。

这是「现代 C++ 实战」系列的第 2 篇。对应 demo:ref/cpp_demo/basics/version_features/。建议先读 第 01 篇:CMake 与现代构建

一、C++ 标准时间线

C++ 不像 Python 那样每年一个大版本,而是 3~5 年发布一次国际标准(由 ISO 委员会制定)。对开发者来说,真正重要的是:编译器支持到了哪个 -std=

标准 发布年份 __cplusplus 常用编译 flag 定位
C++98 / C++03 1998 / 2003 199711L -std=c++03 经典 C++,STL 定型
C++11 2011 201103L -std=c++11 现代 C++ 起点
C++14 2014 201402L -std=c++14 C++11 的小修小补
C++17 2017 201703L -std=c++17 实用工具大爆发
C++20 2020 202002L -std=c++20 语言级现代化
C++23 2023 202302L -std=c++23 实用特性补齐
C++26 2026 202603L -std=c++26 反射、契约、执行框架

几个直觉:

  • C++03 到 C++11 隔了 13 年,变动最大——很多人说的「现代 C++」就是从 C++11 算起。
  • C++14 / C++17 是「好用」版本:不颠覆思维,但日常编码效率明显提升。
  • C++20 是「换引擎」版本:Concepts、Ranges、协程、Modules 等进入标准。
  • C++23 是「补账」版本:expected、print、deducing this 等前几版欠的实用特性陆续落地。
  • C++26 是「2026 新定稿」版本(ISO 2026 年 3 月完成技术定稿):编译期反射、契约(Contracts)、std::execution 异步框架、pack indexing 等进入标准。
  • 本系列 demo 标注了所需标准(C++11~C++26),CMake 里用 CMAKE_CXX_STANDARDset_target_properties 指定即可(见第 01 篇)。

二、C++11:现代 C++ 的起点

C++11 之前,写 C++ 像在开手动挡:内存自己管、线程自己封装、泛型报错看不懂。C++11 一次性补上了现代语言的核心拼图:

类别 代表特性 本系列对应篇
类型系统 autodecltypeenum class 第 06 篇 Lambda
内存管理 unique_ptr / shared_ptr、右值引用、移动语义 第 03–05 篇
泛型与函数式 Lambda、可变参数模板、std::function 第 06 篇
并发 std::threadmutexfuture 第 12 篇
容器与工具 unordered_maparraytuplechrono 各 demo 中广泛使用

version_features/11.cpp 里几乎是一份 C++11 特性清单:decltype、智能指针、右值引用、std::thread、完美转发雏形等。运行它:

1
2
cd ref/cpp_demo/basics/version_features
./build.sh --run-args './build/demo_11'

文件开头有一句:

1
static_assert(__cplusplus == 201103, "");

这行代码的含义是:这个翻译单元必须按 C++11 标准编译,否则直接报错——比运行时才发现问题更早、更干净。

三、C++14 / C++17:实用增强

C++14:让 C++11 更好用

C++14 改动不大,但几个特性非常「省心」:

特性 作用 demo 中的例子
返回值类型推导 auto func() 自动推导返回类型 deduced_return_type()
泛型 Lambda [](auto x){} 参数类型自动推导 14.cpp 中的 lambda 示例
make_unique make_shared 对称,异常更安全 智能指针 demo
二进制字面量 0b1010 位操作更清晰
std::exchange 原子地交换并赋值 移动语义辅助

运行 C++14 demo:

1
./build.sh --run-args './build/demo_14'

C++17:日常开发的工具箱

C++17 是很多人日常项目的「甜点版本」——编译器支持广泛,特性又足够新:

特性 一句话 本系列
结构化绑定 auto [k, v] = pair 第 07 篇
if constexpr 编译期分支,替代 SFINAE 技巧 第 07 / 11 篇
std::optional / variant / any 类型安全的「可能有值」 第 07–08 篇
std::filesystem 跨平台文件路径操作 第 07 篇
类模板参数推导 (CTAD) pair p(1, 2.3) 不用写模板参数 17.cpp
折叠表达式 (args + ...) 可变参数求和 第 07 篇
并行算法 std::execution::par 第 07 篇

17.cpp 里 CTAD 的写法很直观:

1
2
constexpr pair deducted_pair(1, 2.3);   // 推导为 pair<int, double>
vector deduction_guide1_vector(int_vector.begin(), int_vector.end());

运行:

1
./build.sh --run-args './build/demo_17'

四、C++20:语言级现代化

C++20 不是「多加几个函数」,而是改写了写 C++ 的方式

特性 解决什么问题 本系列
Concepts 模板报错像天书 → 约束模板参数 第 11 篇
Ranges 算法 + 迭代器组合冗长 → 管道式链式调用 第 10 篇
Coroutines 异步回调地狱 → co_await 协作式多任务 第 27 篇
Modules 头文件编译慢 → 模块导入(仍在普及中)
std::format printf / iostream 不安全 → 类型安全格式化 第 09 篇
三路比较 <=> 手写 6 个比较运算符 → 自动生成 20.cpp
指定初始化器 指定 .x = 1 初始化 struct 成员 20.cpp

20.cpp 中的三路比较:

1
2
3
static_assert(1 <=> 2 < 0);   // less
static_assert(2 <=> 1 > 0); // greater
static_assert(1 <=> 1 == 0); // equal

C++20 对编译器版本要求更高。macOS 上建议 Apple Clang 14+GCC 10+;若 demo_20 编译失败,先查编译器版本,再对照 cppreference 编译器支持表

1
./build.sh --run-args './build/demo_20'

五、C++23:实用特性补齐

C++23 于 2023 年发布,GCC 14+ / Clang 18+ 已能完整支持大部分特性。几个最值得日常使用的:

特性 说明 本系列
std::expected 类似 Rust 的 Result<T, E>,错误处理更明确 第 08 / 17 篇
std::print / println format + cout 更简洁的输出 第 17 篇
deducing this 成员函数自动推导 this 类型,简化 CRTP 进阶
std::generator 协程生成器,简化迭代器实现 第 27 篇
std::mdspan 多维数组视图,科学计算友好
if consteval 区分编译期与运行时分支 第 09 篇
0uz 字面量 size_t 后缀,消除与 int 比较的符号警告 23.cpp

23.cpp 中的 std::expected 用法:

1
2
3
4
5
6
std::expected<int, ParseError> parse_int(const std::string& s) {
if (s.empty())
return std::unexpected(ParseError::EmptyInput);
// ...
return value; // 成功时直接返回值
}

运行 C++23 demo:

1
./build.sh --run-args './build/demo_23'

本系列第 17 篇会专门跑 cpp23_features demo,那里有更完整的 expected / deducing this 演示。

六、C++26:2026 定稿的新标准

2026 年 3 月,ISO C++ 委员会完成了 C++26 的技术定稿(ISO/IEC 14882:2026)。这是继 C++23 之后最新一版国际标准,几个标志性变化:

特性 说明 编译器支持
编译期反射(Reflection) ^^ 运算符在编译期获取类型元信息 GCC 16+ 实验性
契约(Contracts) pre / post / contract_assert 替代 C 风格 assert GCC 16+ 部分
std::execution Sender/Receiver 异步执行框架 逐步落地
Pack indexing args...[0] 直接索引参数包 Clang 19+ / GCC 15+
内存安全改进 读取未初始化局部变量不再 UB;标准库加固 重编译即生效
<inplace_vector> 固定容量、栈上可扩容向量 逐步落地

26.cpp 中的 pack indexing(C++26 核心语言特性之一):

1
2
3
4
template <typename... Ts>
constexpr auto pack_first(Ts... args) {
return args...[0]; // 直接索引参数包,不再需要递归 / std::get
}

运行 C++26 demo:

1
./build.sh --run-args './build/demo_26'

注意:C++26 刚定稿,各编译器支持仍在快速推进中。Apple Clang 21 已支持 pack indexing 和 std::println,但反射和契约可能还需等待后续版本。新项目不必立刻切 C++26,但应了解方向——本系列第 17 篇及后续会逐步覆盖。

七、编译器怎么选?

不同编译器、不同版本,对标准的支持进度不同。日常开发可以记这张简表:

编译器 推荐最低版本 C++17 C++20 C++23 C++26 常见场景
GCC 14+ ✅ 完整 ✅ 完整 ✅ 大部分 部分 Linux 服务器、Docker
Clang 18+ ✅ 完整 ✅ 完整 ✅ 大部分 部分 macOS、clangd
Apple Clang 16+ (Xcode 16) ✅ 大部分 少量 macOS 本地开发
MSVC VS 2022 17.8+ 大部分 少量 Windows

实用建议:

  1. 新项目默认 C++17,除非明确需要 C++20 特性(Concepts、Ranges、协程等)。
  2. CMake 里写死标准并开启 REQUIRED(第 01 篇),避免静默降级。
  3. CI 与本地编译器尽量一致——Docker 环境就是为了这个(第 00 篇)。
  4. 查某个特性是否可用:cppreference 的 Compiler Support 表,或代码里 #if __cpp_xxx 宏(demo 中大量使用)。

八、demo 导览:version_features

ref/cpp_demo/basics/version_features/ 把各版本特性拆成独立可执行文件:

可执行文件 标准 源文件 主要内容
demo_03 C++11* 03.cpp 关联容器、RAII 雏形、经典 STL
demo_11 C++11 11.cpp auto、智能指针、线程、Lambda
demo_14 C++14 14.cpp 返回值推导、泛型 Lambda
demo_17 C++17 17.cpp CTAD、optional、variant、结构化绑定
demo_20 C++20 20.cpp <=>、指定初始化、协程、bit_cast
demo_23 C++23 23.cpp expected、println、deducing this、if consteval
demo_26 C++26 26.cpp pack indexing、mdspan 多维下标
test_20 C++20 test_20.cpp C++20 特性补充测试

* 注:demo_03 的 CMake 目标实际设为 C++11 编译,但内容展示的是 C++03 时代的惯用法与容器。

CMake 为每个 target 单独指定标准——这正是多版本 demo 共存的关键:

1
2
3
4
5
6
7
8
9
10
11
add_executable(demo_11 11.cpp)
set_target_properties(demo_11 PROPERTIES CXX_STANDARD 11)

add_executable(demo_20 20.cpp)
set_target_properties(demo_20 PROPERTIES CXX_STANDARD 20)

add_executable(demo_23 23.cpp)
set_target_properties(demo_23 PROPERTIES CXX_STANDARD 23)

add_executable(demo_26 26.cpp)
set_target_properties(demo_26 PROPERTIES CXX_STANDARD 26)

一键运行全部

1
2
cd ref/cpp_demo/basics/version_features
./build.sh --run

build.sh --run 会依次编译并执行 build/ 下所有可执行文件。首次编译若 C++20 target 报错,优先检查编译器版本。

建议阅读顺序

  1. demo_03 — 感受「没有智能指针、没有 auto」时代怎么写
  2. demo_11 — 现代 C++ 的「大爆炸」
  3. demo_14demo_17 — 逐步变好用
  4. demo_20 — 语言级现代化
  5. demo_23demo_26 — 最新标准实用特性与前沿方向

九、如何用到本系列后续文章?

把本篇当作目录页,后面每一篇深入一个特性:

篇号 主题 版本 demo
03 移动语义 C++11 right_ref_demo/
04–05 智能指针 C++11 smart_pointers/
06 Lambda C++11/14/20 lambda_demo/
07 C++17 工具箱 C++17 any_demo
09–11 format / Ranges / Concepts C++20 各 demo
12–14 并发 C++11/20 concurrency/
17 C++23 C++23 cpp23_features/
C++26 预览 C++26 version_features/26.cpp

遇到编译错误时,先问自己两个问题:

  1. 这个 demo 需要哪个 -std=c++XX
  2. 我的编译器版本够不够?

十、小结

本篇梳理了 C++ 标准从 03 到 26 的演进路线:

  • C++11 是现代 C++ 的分水岭——智能指针、移动语义、Lambda、线程
  • C++14/17 让日常编码更高效——CTAD、optional、filesystem、并行算法
  • C++20 带来 Concepts、Ranges、协程、format 等语言级变革
  • C++23 补齐 expected、print、deducing this 等实用特性
  • C++26(2026 定稿)引入反射、契约、pack indexing、std::execution
  • version_features demo 按版本拆分(03 → 26),可逐个编译运行

现代 C++ 实战系列第 2 篇完。下一篇我们深入 移动语义与右值引用——std::move 到底在干什么,为什么它能大幅提升性能。

系列导航

篇号 标题 状态
00 环境搭建与项目导览
01 CMake 与现代构建
02 C++ 版本演进一览(本篇)
03 移动语义与右值引用 下一篇

完整大纲见工作区 docs/CPP_SERIES_OUTLINE.md