截至当前(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 字符串
  • 引入 u8stringu8string_viewu8"..." 字面量标准化支持

  • 标准库 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 转换为容器:
`auto vec = r

std::views::enumerate

带索引遍历:
`for (auto [i, val] : v

std::views::chunk

分块视图:
`for (auto chunk : v

std::basic_string::contains

字符串是否包含子串/字符

std::move_only_function

可移动的通用函数包装器(替代部分 std::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

 / aligned_union

弃用(用 alignas + std::byte[] 替代)

volatile

 相关原子操作

弃用(volatile 不用于并发)

std::pointer_traits<void>

移除


五、C++23 vs C++20 对比速查

特性

C++20

C++23

std::expected

std::print

 / println

std::stacktrace

std::generator

❌(需手写)

✅(标准库提供)

std::flat_map

 / flat_set

std::mdspan

UTF-8 源码标准化

部分

✅ 完整支持

if consteval

#elifdef


六、最佳实践建议

  1. 用 std::expected 替代错误码或异常

    (尤其系统编程、嵌入式)

  2. 优先使用 std::print 而非 std::cout

    (更简洁、更快)

  3. 小规模有序数据用 flat_map/flat_set

     提升缓存命中率

  4. 多维数据处理用 mdspan

    (避免裸指针算术)

  5. 协程生成器直接用 std::generator
  6. 崩溃日志中嵌入 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++ 代码!

 欢迎扫描关注,持续交流学习!! 

代码之外的风景:程序员如何平衡工作与生活的艺术

山海重光:当〈山海经〉的神兽踏进芯片,古老幻想在硅基世界涅槃重生

SQLite不止于轻量:揭秘万亿级部署背后的核心力量​

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐