C++23--C++20 的成熟补全版
截至当前(2025年12月),C++23(ISO/IEC 14882:2023) 已正式发布,是继 C++20 之后的又一次重要演进。虽然没有像 C++11 或 C++20 那样引入“四大支柱”级特性,但 C++23 聚焦于 完善标准库、提升语言一致性、增强实用性与开发者体验,并首次引入了多个长期呼声极高的功能(如 std::expected、UTF-8 支持标准化等)。
以下是对 C++23 新特性的全面、结构化总结,涵盖语言核心、标准库、工程价值及典型用例。
一、设计目标
- 填补 C++20 的空白
(如错误处理、文本编码)
- 提升标准库的完整性与易用性
- 强化 constexpr 和模板能力
- 改善可移植性与国际化支持
✅ C++23 被视为 “C++20 的成熟补全版”,更适合生产环境全面采用。
二、语言核心新特性
1. if consteval —— 编译期条件分支
替代不可靠的 if constexpr (std::is_constant_evaluated()),明确区分编译期与运行期逻辑:
consteval int compile_time_only() { return 42; }
int hybrid_func(int n) {
if consteval {
// 仅在常量求值上下文中执行
return compile_time_only();
} else {
// 运行期路径
return n * 2;
}
}
constexpr int a = hybrid_func(10); // 调用 compile_time_only()
int b = hybrid_func(10); // 调用 n*2
✅ 比
std::is_constant_evaluated()更清晰、更安全。
2. #elifdef / #elifndef —— 预处理器增强
简化嵌套宏条件判断
#if defined(A)
// ...
#elifdef B // 等价于 #elif defined(B)
// ...
#elifndef C // 等价于 #elif !defined(C)
// ...
#endif
✅ 减少括号和
defined重复,提升可读性。
3. 允许非静态数据成员初始化器用于聚合初始化
struct Point {
int x = 0; // 默认值
int y = 0;
};
Point p1{}; // {0, 0}
Point p2{1}; // {1, 0} ← C++23 允许!
Point p3{1, 2}; // {1, 2}
⚠️ C++20 中
p2{1}是非法的(因存在默认成员初始化器),C++23 修复此限制。
4. constexpr 增强
-
允许
va_list在constexpr中使用(有限制) -
放宽对 虚函数、动态转换 的限制(仍需满足常量上下文)
三、标准库重大新增与改进
1. std::expected<T, E> —— 错误处理的官方方案 ✅(重磅!)
终于迎来类似 Rust 的 Result<T, E> 或 Haskell 的 Either:
#include <expected>
#include <string>
#include <iostream>
std::expected<int, std::string> divide(int a, int b) {
if (b == 0)
return std::unexpected("Division by zero");
return a / b;
}
auto result = divide(10, 0);
if (result) {
std::cout << "Result: " << *result;
} else {
std::cout << "Error: " << result.error();
}
✅ 替代:
返回错误码 + 输出参数
抛异常(性能敏感场景不适用)
自定义
StatusOr类型
📌 与
std::optional对比:optional表示“有或无”,expected表示“成功或失败(带错误信息)”。
2. UTF-8 作为源文件和字符串字面量的首选编码
char8_t正式用于 UTF-8 字符串-
引入
u8string、u8string_view、u8"..."字面量标准化支持 -
标准库 I/O 支持 UTF-8(平台相关,但语义明确)
std::u8string utf8_msg = u8"你好,世界!";
std::cout << reinterpret_cast<const char*>(utf8_msg.c_str());
⚠️ 仍需注意终端/控制台的编码设置,但语言层面已统一。
3. std::mdspan —— 多维数组视图(N-D Span)
用于科学计算、图像处理、张量操作等场景:
#include <mdspan>
#include <vector>
std::vector<double> data(12); // 3x4 矩阵
std::mdspan mat{data.da, 3, 4};
mat(1, 2) = 3.14; // 设置第2行第3列
✅ 无所有权、零拷贝、支持布局策略(row-major / column-major)。
4. std::flat_set / std::flat_map —— 基于 vector 的有序容器
内存连续、缓存友好,适合小规模或只读场景:
#include <flat_set>
#include <flat_map>
std::flat_set<int> s = {3, 1, 4, 1, 5};
std::flat_map<std::string, int> m = {{"a", 1}, {"b", 2}};
✅ 内部使用
std::vector存储,插入 O(n),查找 O(log n),但遍历速度远快于std::set。
5. std::generator —— 协程生成器(标准库原生支持)
无需手动实现 promise_type,直接写生成器:
#include <generator>
std::generator<int> iota(int start) {
for (int i = start; ; ++i)
co_yield i;
}
for (int x : iota(10) | std::views::take(3)) {
std::cout << x << " "; // 10 11 12
}
✅ 极大简化协程生成器的使用,与 Ranges 无缝集成。
6. std::print / std::println —— 直接输出(无需包含 <iostream>)
基于 std::format 的轻量级输出:
#include <print>
std::print("Hello {}!\n", "C++23");
std::println("Pi ≈ {:.2f}", 3.14159); // 自动换行
✅ 性能优于
std::cout,线程安全,支持格式化。
7. std::stacktrace —— 获取运行时调用栈
用于调试、日志、崩溃报告:
#include <stacktrace>
#include <iostream>
void foo() {
std::cout << std::stacktrace::current();
}
输出示例:
0# foo in ./a.out
1# main in ./a.out
⚠️ 需要编译器支持(GCC ≥12, MSVC ≥2022)和符号信息。
8. 其他实用工具
|
特性 |
说明 |
|---|---|
std::unreachable() |
告诉编译器某段代码不可达(优化提示) |
std::ranges::to |
将 range 转换为容器: |
std::views::enumerate |
带索引遍历: |
std::views::chunk |
分块视图: |
std::basic_string::contains |
字符串是否包含子串/字符 |
std::move_only_function |
可移动的通用函数包装器(替代部分 |
// contains 示例
if (str.contains("error")) { /* ... */ }
// ranges::to 示例
auto squares = numbers
| std::views::transform([](int x) { return x*x; })
| std::ranges::to<std::vector>();
四、弃用与移除(C++23)
|
特性 |
状态 |
|---|---|
std::aligned_storage
/ |
弃用(用 |
volatile
相关原子操作 |
弃用( |
std::pointer_traits<void> |
移除 |
五、C++23 vs C++20 对比速查
|
特性 |
C++20 |
C++23 |
|---|---|---|
std::expected |
❌ |
✅ |
std::print
/ |
❌ |
✅ |
std::stacktrace |
❌ |
✅ |
std::generator |
❌(需手写) |
✅(标准库提供) |
std::flat_map
/ |
❌ |
✅ |
std::mdspan |
❌ |
✅ |
|
UTF-8 源码标准化 |
部分 |
✅ 完整支持 |
if consteval |
❌ |
✅ |
#elifdef |
❌ |
✅ |
六、最佳实践建议
- 用
std::expected替代错误码或异常(尤其系统编程、嵌入式)
- 优先使用
std::print而非std::cout(更简洁、更快)
- 小规模有序数据用
flat_map/flat_set提升缓存命中率
- 多维数据处理用
mdspan(避免裸指针算术)
- 协程生成器直接用
std::generator - 崩溃日志中嵌入
std::stacktrace
七、总结
C++23 是“务实主义”的胜利:
它没有追求炫技,而是聚焦于开发者每天都会遇到的问题——错误处理、文本编码、容器选择、调试支持、I/O 简化。
这些看似“小”的改进,恰恰是提升工程效率和代码健壮性的关键。
随着主流编译器(GCC 13+、Clang 16+、MSVC 17.6+)逐步完整支持 C++23,新项目应优先考虑采用 C++23。
如需深入探讨以下主题,欢迎关注沟通交流:
std::expected与异常的选型指南?
flat_map与
unordered_map性能对比?-
如何在旧编译器上模拟
std::print? -
C++26 的前瞻特性(如
std::execution、模式匹配)?
祝你写出更安全、更高效、更现代的 C++ 代码!
欢迎扫描关注,持续交流学习!!
更多推荐
所有评论(0)