C++26 深度实战:反射、合约、内存安全与 Sender/Receiver——当 C++ 终于补齐了最后四块短板
一、背景:C++26 为何被称为"十年最大变革"
2026 年 3 月,ISO C++ 标准委员会正式冻结 C++26(内部代号 C++2c)特性。Herb Sutter 用"自 C++11 以来最具冲击力的一次发布"来形容它——这话不夸张。
回顾 C++ 的版本史:
| 版本 | 发布年 | 核心变革 |
|---|---|---|
| C++98 | 1998 | 模板、STL 标准化 |
| C++11 | 2011 | 移动语义、lambda、智能指针 |
| C++14 | 2014 | 泛型 lambda、返回值类型推导 |
| C++17 | 2017 | if constexpr、结构化绑定、filesystem |
| C++20 | 2020 | 概念、协程、范围库、模块 |
| C++23 | 2023 | std::print、std::expected、deducing this |
| C++26 | 2026 | 反射、合约、std::execution、内存安全 |
C++14 和 C++23 顶多算"小修小补",C++20 虽然引入了协程和概念,但协程没有配套调度框架,概念也只是类型约束的语法糖。而 C++26 切入的是三个 C++ 诞生以来从未真正解决的"历史遗留问题":
- 元编程靠宏和 SFINAE——C++ 的模板元编程是图灵完备的,但写起来像在跟编译器玩文字游戏
- 内存安全靠人工审查——悬垂指针、未初始化变量、越界访问,C++ 在这块欠了几十年的债
- 异步编程靠各路第三方库——没有统一的调度模型,libuv、boost.asio、各种 thread pool 各自为政
C++26 对这三个问题给出了语言级的回答,再加上"合约"(Contracts)作为接口层面的契约式设计保障,这就是 Herb Sutter 口中的"Fab Four"。
这篇文章不会泛泛罗列特性列表,而是从工程视角深入每个核心特性:它解决什么问题、怎么用、内部机制是什么、迁移到生产环境要注意什么。
二、反射(Reflection):编译期"代码生成代码"的终极武器
2.1 背景:为什么 C++ 需要反射?
在 C++26 之前,如果你想写一个通用的 JSON 序列化工具,你有三条路:
方案 A:手动实现
struct Person {
std::string name;
int age;
std::optional<std::string> email;
};
nlohmann::json to_json(const Person& p) {
return {
{"name", p.name},
{"age", p.age},
{"email", p.email}
};
}
每个结构体都要手写——如果有 50 个结构体,50 次重复劳动。枯燥且容易漏字段。
方案 B:宏
#define DEFINE_SERIALIZABLE(Type, ...) /* 宏魔法 */
宏不可调试、不支持嵌套、IDE 不能补全、容易产生 ODR 违规。
方案 C:SFINAE + 模板特化
template<typename T, typename = void>
struct has_to_json : std::false_type {};
template<typename T>
struct has_to_json<T, std::void_t<decltype(to_json(std::declval<T>()))>>
: std::true_type {};
这段代码在 C++ 社区被称为"天书"。对绝大多数开发者而言,SFINAE 是只读不写的黑魔法。
这三条路都不好走。C++26 的反射基于提案 P2996R13,核心思想是:让类型变成编译期可查询的值。
2.2 基础用法:枚举结构体成员
使用 <refl.hpp>(C++26 标准提案中的头文件):
#include <refl.hpp>
#include <iostream>
struct Person {
std::string name;
int age;
bool is_active;
};
int main() {
// 编译期反射:遍历 Person 的所有成员
// refl::type<Person> 是一个编译期类型对象
// .members 返回该类型所有可反射成员的元组
constexpr auto members = refl::type<Person>::members;
// 在编译期展开,零运行时开销
refl::for_each(members, []<typename M>(M member) {
std::cout << "成员名: " << M::name << "\n";
std::cout << "偏移量: " << M::offset << "\n";
// M::type 是成员的类型(编译期)
});
}
输出:
成员名: name
偏移量: 0
成员名: age
偏移量: 32 // 取决于 ABI 和填充
成员名: is_active
偏移量: 36
注意这里的关键:refl::for_each 在编译期展开。如果结构体有 3 个字段,编译器会生成 3 个独立的函数调用,而不是一个带 runtime 循环的版本。这意味着反射的运行时成本为 零。
2.3 深度实战:通用 JSON 序列化器
有了反射,写一个通用序列化器只需要 30 行代码:
#include <refl.hpp>
#include <nlohmann/json.hpp>
#include <string>
#include <vector>
// 序列化:将任意可反射类型转为 JSON
template<refl::type T>
nlohmann::json serialize(const T& obj) {
nlohmann::json j;
// 编译期遍历所有成员
refl::for_each(refl::type<T>::members, [&]<typename M>(M member) {
using MemberType = typename M::type;
const auto& value = member.get(obj); // 通过偏移量获取成员值
j[M::name] = value; // 序列化为 JSON
});
return j;
}
// 反序列化:将 JSON 转为类型实例
template<refl::type T>
T deserialize(const nlohmann::json& j) {
T obj;
refl::for_each(refl::type<T>::members, [&]<typename M>(M member) {
using MemberType = typename M::type;
if (j.contains(M::name)) {
member.get(obj) = j[M::name].get<MemberType>();
}
});
return obj;
}
// 用法
struct Config {
std::string host;
int port = 8080;
bool tls = true;
};
int main() {
Config cfg{"example.com", 443, true};
auto j = serialize(cfg);
std::cout << j.dump(2) << "\n";
// {
// "host": "example.com",
// "port": 443,
// "tls": true
// }
auto cfg2 = deserialize<Config>(j);
assert(cfg2.host == "example.com");
}
这比手写 to_json 省了 50 倍的工作量,而且零运行时开销——编译器把 refl::for_each 展开成三条直接的赋值语句。
2.4 编译期类型查询
反射不仅仅是遍历成员,还支持丰富的类型内省:
#include <refl.hpp>
#include <type_traits>
struct MyClass {
int x;
std::string y;
void foo() {}
static const int z = 42;
};
int main() {
constexpr auto type_info = refl::type<MyClass>;
// 查询类型属性
static_assert(type_info.size == 2); // 数据成员数量
static_assert(type_info.has_member<"x">); // 是否有成员 x
static_assert(type_info.member<"x">.is_public); // 是否 public
// 编译期获取成员类型
using XType = decltype(type_info.member<"x">)::type;
static_assert(std::is_same_v<XType, int>);
// 查询是否有某个方法
constexpr bool has_foo = type_info.has_method<"foo">;
static_assert(has_foo);
// 查询静态成员
constexpr auto z_val = type_info.member<"z">.get();
static_assert(z_val == 42);
}
2.5 反射内部机制
C++26 反射的底层机制很有意思。提案 P2996R13 引入了一种叫 refl::type<T> 的编译期类型对象。它本质上是一个满足特定约束的 constexpr 值——你可以把它理解成"类型的值表示"。
关键概念:
- type-as-value: 类型本身可以作为一个 constexpr 值传递
- member enumeration: 在编译期枚举结构体的所有可反射成员(数据成员、方法、嵌套类型)
- semantic introspection: 查询成员的访问控制、偏移量、类型
实现上,编译器为每个类型生成一个隐式的反射描述符表,类似于 RTTI 的 type_info,但区别在于:
- RTTI 只在运行时可用,且只能查询类型名称
- C++26 反射在编译期可用,且可以查询成员结构
这也解释了为什么 C++26 反射不会增加运行时开销——所有查询在编译期完成,运行时没有任何额外的虚函数调用或表查找。
2.6 设计陷阱与最佳实践
陷阱 1:反射不是 RTTI
反射只对编译期已知的类型有效。你不能在运行时根据字符串创建类型实例(这是 C#/Java 的运行时反射,C++ 不打算支持)。
陷阱 2:模板膨胀风险
过度使用反射生成泛化工具(如序列化、ORM)可能导致模板膨胀。每个 refl::type<T> 实例都会生成一份展开代码。
建议:显式实例化常用的类型组合,避免在头文件中暴露给所有 TU。
陷阱 3:访问控制边界
反射遵守 C++ 的访问控制规则。private 成员在反射查询中会被隐藏,除非在 friend 声明中授权。
class Secret {
private:
int hidden_value; // 反射不可见(除非有 friend refl::reflect<Secret>)
public:
int visible;
};
最佳实践:
- 优先用反射替代宏和 SFINAE
- 泛化工具(序列化、比较、打印)放在
.cpp文件中显式实例化 - 不要试图用反射实现运行时多态——C++ 有虚函数就是干这个的
三、内存安全:重编即安全,Google 内部数据已证明
3.1 C++ 内存安全的痛点
C++ 被诟病最多的就是内存不安全。看看一年有多少 CVE 跟内存相关——2025 年微软的安全公告中,约 70% 的漏洞根源是内存安全问题。
核心痛点有三个:
痛点 1:未初始化变量
int* p;
if (some_condition) {
p = new int(42);
}
// 如果 some_condition 为 false,p 未初始化
// 在 C++26 之前,这是 UNDEFINED BEHAVIOR
*p = 10; // 可能直接 crash
痛点 2:越界访问
std::vector<int> v = {1, 2, 3};
v[100] = 42; // operator[] 不做边界检查,UB
痛点 3:悬垂指针
int* p = new int(42);
delete p;
*p = 10; // use-after-free
3.2 C++26 的两大安全改进
3.2.1 未初始化变量不再 UB
这是 C++26 最被低估的变化。提案 P2759R2 将"读取未初始化局部变量"从未定义行为(UB)降级为未指定值(unspecified value)。
// C++26 之前:UB,编译器可以假设这段代码不会执行
// C++26:未指定值,但不会崩溃
int x; // 未初始化
int y = x + 1; // C++26: y 是有效 int(值未指定),不会 UB
这意味着什么?在 C++26 模式下重新编译代码,大量因为未初始化变量导致的"偶发性崩溃"会直接消失。Google 的内部数据显示:
"仅在 Google,这项技术就已经修复了超过 1000 个 Bug,预计每年可以预防 1000 到 2000 个新 Bug 的产生,并将整个生产环境的段错误(Segfault)率降低了 30%。"
3.2.2 加固标准库(Hardened Standard Library)
Google 和 Apple 分别贡献了它们内部已经运行多年的"加固"标准库实现:
// 传统 operator[] — 不做边界检查
std::vector<int> v = {1, 2, 3};
v[100] = 42; // 之前:UB,可能悄悄损坏内存
// C++26 加固模式 — 自动边界检查
// 在 C++26 模式下编译
std::vector<int> v = {1, 2, 3};
v[100] = 42; // 抛出 std::out_of_range 异常
关键在于这种加固零配置——只要用 C++26 模式重新编译,所有 std::vector、std::string、std::span 等容器的边界检查自动开启。
性能影响?Google 的测试显示平均 5-15% 的开销,但换来的是 30% 的 segfault 降低。在安全敏感场景(如网络服务的数据解析层),这完全值得。
3.3 生产级迁移建议
| 场景 | 建议 |
|---|---|
| 全新项目 | 默认启用 C++26 编译模式,利用加固标准库 |
| 遗留代码 | 先在测试环境用 C++26 模式编译,修复所有 hardening 异常 |
| 性能关键路径 | 对热点路径用 std::unchecked API 手动关掉边界检查 |
| 嵌入式/RT 系统 | 谨慎启用,评估 5-15% 开销是否可接受 |
// 性能关键路径:手动跳过边界检查
void process_fast(const std::vector<int>& v) {
// C++26 中,at() 做边界检查,operator[] 在加固模式下也做
// 如果确定数据有效,可以用 data() 直接访问
for (size_t i = 0; i < v.size(); ++i) {
do_something(v.data()[i]); // 无边界检查
}
}
四、合约(Contracts):代码里的"法律条文"
4.1 契约式设计
契约编程(Design by Contract)的思想来自 Eiffel 语言。核心概念:
- 前置条件(precondition):调用函数前必须满足的条件
- 后置条件(postcondition):函数返回后必须保证的条件
- 不变量(invariant):在整个函数执行过程中保持不变的条件
在 C++26 之前,你要么手动写 if-return,要么用 assert:
// 老方法 1:手动防御
int divide(int a, int b) {
if (b == 0) {
throw std::invalid_argument("division by zero");
}
return a / b;
}
// 老方法 2:assert
int divide(int a, int b) {
assert(b != 0 && "division by zero");
return a / b;
}
两种都有问题:手动防御在 Release 模式下也存在(性能开销),assert 在 Release 模式下直接消失(失去安全保障)。
4.2 C++26 合约语法
C++26 的合约基于提案 P2900R7,引入 pre、post 关键字:
#include <contracts> // 合约头文件(C++26 新增)
// 前置条件 + 后置条件
int divide(int a, int b)
[[pre: b != 0]] // 调用前保证:b 不为 0
[[post r: r * b == a]] // 返回后保证:结果 * 除数 == 被除数
{
return a / b;
}
更复杂的例子——队列的操作契约:
template<typename T>
class BoundedQueue {
std::vector<T> data_;
size_t head_ = 0, tail_ = 0;
size_t capacity_;
public:
explicit BoundedQueue(size_t cap) : capacity_(cap) {
data_.resize(cap);
}
void push(const T& value)
[[pre: !full()]] // push 前队列不满
[[post: !empty()]] // push 后队列不空
[[post: size() == old_of(size()) + 1]] // size 增加 1
{
data_[tail_ % capacity_] = value;
++tail_;
}
T pop()
[[pre: !empty()]] // pop 前队列不空
[[post: size() == old_of(size()) - 1]] // size 减少 1
{
T val = data_[head_ % capacity_];
++head_;
return val;
}
bool full() const {
return size() == capacity_;
}
bool empty() const {
return head_ == tail_;
}
size_t size() const {
return tail_ - head_;
}
};
4.3 合约的三种检查级别
合约不是简单的二进制开关。C++26 定义了四个检查级别:
| 级别 | 宏 | 行为 | 适用场景 |
|---|---|---|---|
default | 无 | Debug 模式检查,Release 默认开启 | 通用开发 |
audit | [[pre audit: ...]] | 所有模式检查,可能较重 | 安全关键代码 |
axiom | [[pre axiom: ...]] | 不检查,仅文档作用 | 纯语义约束 |
off | -Dcontracts=off | 全局关闭 | 性能极致优化 |
// audit 级别:即使 Release 也必须检查
void transfer_money(Account& from, Account& to, double amount)
[[pre audit: from.balance() >= amount]] // 扣款前余额足够
[[pre: amount > 0]] // default 级别
[[post audit: from.balance() + amount == old_of(from.balance())]] // 金额守恒
{
from.withdraw(amount);
to.deposit(amount);
}
4.4 生产级最佳实践
合约不是异常处理:合约描述的是"不应该发生"的情况(bug),而不是"可能发生"的情况(如网络超时)。可能的错误用异常或
std::expected。不写副作用:合约里的表达式应该没有副作用——因为 Audit 级别可能求值多次,Axiom 级别可能不求值。
区分内部和外部合约:public API 用 audit 级别,内部实现用 default 级别。
class DatabaseConnection {
public:
// 外部接口:audit 级别,Release 也检查
void execute(const std::string& sql)
[[pre audit: !sql.empty()]]
[[pre audit: is_connected()]]
{
// ...
}
private:
// 内部实现:default 级别
void parse_query(const std::string& sql)
[[pre: !sql.empty()]]
{
// ...
}
};
五、std::execution:C++ 的"亲儿子"并发模型
5.1 背景:C++ 异步编程的割裂史
C++20 引入了协程,但只提供了 co_await 语法,没有统一的调度层。这就好比给了你方向盘和油门,但没有变速箱和传动轴。
现实很残酷:
- libuv(Node.js 的底层)— 纯 C 的 event loop
- boost.asio — 强大但复杂,proactor 模型
- Intel TBB — 专为并行计算设计
- 各家手写的 thread pool — 重复造轮子
C++26 的 std::execution(Sender/Receiver 模型) 就是要统一这一切。
5.2 Sender/Receiver 核心概念
Sender/Receiver 模型的核心思想是声明式异步编程——你描述"做什么",而不是"怎么做"。
说人话:你声明一个异步任务图,std::execution 负责在适当的执行上下文中调度它。
四个核心概念:
- Sender:可以产生值的异步操作
- Receiver:接收 Sender 产生值的回调
- Scheduler:决定"在哪里"执行(线程池、event loop、GPU 队列等)
- Sender Adaptor:组合 Singers 的操作符(
then、when_all、let_value等)
5.3 实战:声明式异步 Web 服务
#include <execution>
#include <iostream>
#include <expected>
// stdexec 是 C++26 标准 execution 库的参考实现命名空间
namespace stdexec = std::execution;
// 异步 HTTP 请求(伪代码)
auto fetch_url(std::string url) -> stdexec::sender auto {
return stdexec::just(url)
| stdexec::then([](std::string u) {
return http_get(u); // 假设这是一个异步 HTTP 客户端
});
}
// 并行处理三个 API 请求并聚合结果
int main() {
// 创建一个 run_loop(类似 Node.js 的 event loop)
stdexec::run_loop ctx;
auto scheduler = ctx.get_scheduler();
// 声明一个异步任务图
auto task = stdexec::when_all(
fetch_url("https://api.example.com/users"),
fetch_url("https://api.example.com/posts"),
fetch_url("https://api.example.com/comments")
) | stdexec::then([](auto users, auto posts, auto comments) {
// 三个 API 全部完成后,聚合结果
return aggregate(users, posts, comments);
}) | stdexec::continue_on(scheduler); // 切换回主 event loop
// 启动任务
auto [result] = stdexec::sync_wait(task).value();
std::cout << "聚合结果: " << result << "\n";
}
这段代码的核心价值:when_all 自动将三个 HTTP 请求并行发出,等全部完成后调用 then 聚合。不需要手动管理线程、future、回调——全部由 framework 调度。
5.4 高级模式:流式处理与背压
真正的价值在于声明式描述复杂异步流程:
// 流式数据处理管线
auto process_stream = stdexec::just()
| stdexec::then([] { return open_connection(); })
| stdexec::let_value([](auto conn) {
return read_stream(conn) // 返回一个"异步的流"(多个值)
| stdexec::then([](auto chunk) {
return transform(chunk);
})
| stdexec::then([](auto transformed) {
return write_to_db(transformed);
})
| exec::repeat_n(1000) // 重复 1000 次
| stdexec::upon_error([](auto e) {
log_error(e);
return 0;
});
});
注意 背压(backpressure) 是内建的——慢的消费者会自动让快的生产者等待,不会出现 OOM。
5.5 与 Go goroutine 和 Rust async 的对比
| 特性 | C++26 Sender/Receiver | Go goroutine | Rust async/await |
|---|---|---|---|
| 抽象层次 | 声明式任务图 | 轻量级线程 | 协程语法 |
| 调度控制 | 精确(Scheduler) | 隐式(runtime) | 通过 executor |
| 背压 | 原生支持 | 需要手写 channel | 通过 Stream trait |
| 零成本抽象 | ✅(编译期展开) | ❌(有 runtime 栈) | ✅ |
| 错误处理 | 内建(set_error) | error 返回值 | Result 类型 |
| 学习曲线 | 陡峭 | 平缓 | 中等 |
5.6 生产部署注意事项
- 选择合适的 Scheduler:GUI 应用用主线程 scheduler,计算密集用 thread pool,I/O 密集用 epoll/iouring scheduler
- 避免过长的 task chain:每个 pipeline 阶段都有上下文切换成本
- 错误处理全覆盖:Sender 的三种结果(value/error/stopped)都要处理
// 完整的错误处理
auto safe_task = stdexec::just()
| stdexec::then(do_something_risky)
| stdexec::upon_error([](std::exception_ptr e) {
try { std::rethrow_exception(e); }
catch (const std::exception& ex) {
std::cerr << "出错: " << ex.what() << "\n";
}
return fallback_value;
})
| stdexec::upon_stopped([] {
std::cerr << "任务被取消\n";
return default_value;
});
六、其他值得关注的小特性
6.1 constexpr placement new
C++26 允许在编译期使用 placement new 管理内存:
// C++26: constexpr placement new
struct alignas(alignof(int)) Storage {
std::byte buf[sizeof(int)];
};
constexpr int create_value() {
Storage s;
int* p = new (s.buf) int(42);
int result = *p;
p->~int(); // 必须手动析构
return result;
}
static_assert(create_value() == 42);
这对编译期容器的实现至关重要。
6.2 结构化绑定增强
可以在 if/switch 条件中直接结构化绑定:
// C++26: 条件中结构化绑定
if (auto [x, y] = get_point(); x > 0 && y > 0) {
std::cout << "第一象限: (" << x << ", " << y << ")\n";
} else if (x < 0 && y > 0) {
std::cout << "第二象限\n";
}
// 另一个例子:结合 optional
if (auto [value, error] = try_parse("42"); !error) {
std::cout << "解析成功: " << value << "\n";
}
6.3 类型协议扩展(Customization Point Objects)
标准库类型现在可以"声明"它们支持某些协议:
// tuple-like 协议扩展到更多类型
template<>
struct std::tuple_size<Complex> : std::integral_constant<size_t, 2> {};
template<size_t I>
struct std::tuple_element<I, Complex> {
using type = double;
};
template<size_t I>
double get(const Complex& c) {
if constexpr (I == 0) return c.real();
else return c.imag();
}
// 现在 Complex 可以用于结构化绑定
Complex c{3.0, 4.0};
auto [re, im] = c; // C++26: OK
七、编译器支持与迁移指南
7.1 当前编译器支持状态(2026 年 7 月)
| 编译器 | 版本 | 反射 | 合约 | std::execution | 内存安全 |
|---|---|---|---|---|---|
| GCC | 15+ | ✅ 95% | ✅ 90% | 🚧 70% | ✅ |
| Clang | 19+ | ✅ 85% | ✅ 85% | 🚧 60% | 🚧 |
| MSVC | 19.50+ | 🚧 60% | 🚧 50% | 🚧 40% | ✅ |
编译开启:
# GCC
g++ -std=c++26 -fcontracts main.cpp -o main
# Clang
clang++ -std=c++26 -fcontracts main.cpp -o main
# MSVC
cl /std:c++26 main.cpp
7.2 渐进式迁移策略
不是所有人都能在 2026 年直接切到 -std=c++26。推荐渐进策略:
阶段 1(1-3 个月):安全先行
1. 在 CI/CD 中增加 C++26 编译的测试矩阵
2. 定位所有 hardening 异常(边界检查)
3. 修复未初始化变量问题
阶段 2(3-6 个月):引入合约
1. 在新的 public API 中加上 [[pre:]] / [[post:]]
2. 将关键路径的 assert() 迁移到合约
3. 用 axiom 级别的合约做文档
阶段 3(6-12 个月):使用反射
1. 替换现有的宏序列化
2. 替换 SFINAE-based type traits
3. 构建通用的泛化工具(序列化、比较、hash)
阶段 4(12+ 个月):std::execution
1. 替换现有的 thread pool 实现
2. 将 pipeline 式的异步逻辑用 Sender/Receiver 重写
3. 评估性能(多数场景优于手写调度)
7.3 一个实际迁移案例
以 JSON 序列化重写为例,看 C++26 如何减少 70% 的模板代码:
// Before (C++20): 手动特化每个类型
template<>
nlohmann::json to_json(const Person& p) {
return {{"name", p.name}, {"age", p.age}};
}
template<>
nlohmann::json to_json(const Address& a) {
return {{"city", a.city}, {"zip", a.zip}};
}
// 20 个结构体 → 20 个手工特化
// After (C++26): 一行通用实现
template<refl::type T>
nlohmann::json to_json(const T& obj) {
return serialize(obj); // 自动反射所有成员
}
// 所有结构体自动支持
八、总结与展望
8.1 C++26 回答了三个问题
- 元编程能不靠黑魔法吗? → 反射让编译期编程像普通函数调用一样自然
- C++ 能安全吗? → 未初始化变量降级 + 加固标准库,一行代码不改就能提升安全性
- 异步能不靠第三方吗? → Sender/Receiver 提供了统一、零成本的异步调度模型
加上合约,这四个特性构成了 C++ 诞生四十年来最系统的一次升级。
8.2 该不该学?
如果你在 C++ 生态内:必须学。C++26 不是可选项,是这个语言自我革新的必然方向。2027 年的时候不会 C++26 反射写序列化,就像 2021 年不会 C++17 if constexpr。
如果你在用 Go/Rust 思考是否转 C++:C++26 让 C++ 更接近 Rust 的内存安全保证,但学习曲线依然陡峭。反射和合约减轻了元编程的痛苦,但没有改变 C++ "要极致性能就必须理解底层"的本质。
如果你是学生/新手:不建议以 C++26 为起点入门。反射和 Sender/Receiver 的前提是理解模板、内存模型和并发——先学好 C++17/20 的基础。
8.3 未来展望
C++ 的演进方向已经很明显:把运行时负担往编译期转移。反射、constexpr 增强、编译期内存管理都是这个趋势。下一个版本(C++29)预计会在反射上继续深化,比如反射驱动的序列化成为标准库的一部分。
C++ 没有选择像 Go 那样"断舍离",也没有像 Rust 那样"偏执于安全",而是选择了"我全都要"的路线。这种贪婪让它永远不可能变成一门"易学"的语言,但也让它保住了系统编程王座的位置。
你想拥有极致性能,就必须拥抱复杂性。C++26 的史诗级更新把这条路上的难度又加高了一个等级,但也给了真正用到极致的人更趁手的工具。
参考资料:
- Herb Sutter, "C++26 Is Done" — https://herbsutter.com/2026/03/29/c26-is-done-trip-report-march-2026-iso-c-standards-meeting-london-croydon-uk/
- P2996R13 — C++26 Reflection
- P2900R7 — Contracts for C++
- P2300R7 — std::execution
- P2759R2 — Uninitialized local variables