C++23 是 C++ 标准的又一次重要更新,既在语言层面做了细致的优化,又在标准库中引入了大量实用的新特性。本文聚焦两个最受关注的改进:协程(Coroutines)以及 constexpr 的进一步扩展。通过实例代码,帮助读者快速上手,并在项目中灵活运用。
一、协程(Coroutines)快速入门
1.1 协程的核心概念
协程是“轻量级协作式线程”,允许函数在执行过程中暂停并恢复,从而实现异步编程、生成器等功能。C++23 通过引入 std::suspend_always、std::suspend_never、std::yield_value 等工具,让协程更易于使用。
1.2 基础协程例子:整数序列生成器
#include <iostream>
#include <coroutine>
#include <optional>
template<typename T>
struct Generator {
struct promise_type;
using handle_type = std::coroutine_handle <promise_type>;
struct promise_type {
T value_;
std::optional <T> current_;
auto get_return_object() { return Generator{handle_type::from_promise(*this)}; }
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
std::suspend_always yield_value(T value) {
current_ = value;
value_ = std::move(value);
return {};
}
void return_void() {}
void unhandled_exception() { std::terminate(); }
};
handle_type coro_;
explicit Generator(handle_type h) : coro_(h) {}
~Generator() { if (coro_) coro_.destroy(); }
bool next() {
if (!coro_.done()) coro_.resume();
return !coro_.done();
}
T value() const { return *coro_.promise().current_; }
};
Generator <int> count_up_to(int limit) {
for (int i = 1; i <= limit; ++i)
co_yield i;
}
int main() {
auto gen = count_up_to(5);
while (gen.next()) {
std::cout << gen.value() << ' ';
}
// 输出: 1 2 3 4 5
}
此示例演示了如何通过 co_yield 实现生成器,C++23 中 std::suspend_always 让协程的挂起点更直观。
1.3 协程在异步 IO 中的应用
借助 std::async、std::future,结合协程可以写出更直观的异步代码:
#include <iostream>
#include <coroutine>
#include <future>
std::future <int> async_add(int a, int b) {
co_return a + b;
}
int main() {
auto fut = async_add(3, 4);
std::cout << "Result: " << fut.get() << '\n';
}
协程让异步编程的逻辑结构更接近同步代码,降低了回调地狱。
二、constexpr 的进一步扩展
2.1 constexpr 递归模板更安全
C++23 对 constexpr 的递归模板调用做了更严格的检查,减少了编译期错误:
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
static_assert(factorial(5) == 120);
编译器会在编译期计算结果,若出现无效递归会给出清晰错误提示。
2.2 constexpr 动态内存
C++23 引入 std::pmr::monotonic_buffer_resource 在 constexpr 环境下可用,允许在编译期进行内存分配:
#include <memory_resource>
#include <array>
constexpr std::pmr::monotonic_buffer_resource pool;
constexpr std::pmr::polymorphic_allocator <int> alloc(&pool);
constexpr std::vector<int, std::pmr::polymorphic_allocator<int>> vec{alloc, {1,2,3,4,5}};
static_assert(vec.size() == 5);
这为编译期生成复杂数据结构提供了可能。
2.3 constexpr 与多线程
C++23 允许在 constexpr 环境下使用 std::thread 的构造函数(但不执行)。这为在编译期验证线程安全性提供了工具:
constexpr void check_thread_safety() {
std::thread t([]{ /* 线程工作 */ });
// 编译期检查构造是否合法
}
三、实践建议
- 模块化:在 C++23 中结合协程和模块化,减少编译时间。将协程实现放在模块中,避免每次编译都要重新编译协程代码。
- constexpr 静态数据:利用 constexpr 动态内存生成编译期常量表,适用于配置系统或生成固定算法表。
- 协程与异步 IO:在网络或文件 IO 场景,使用
co_await与异步函数组合,写出更易读的非阻塞代码。 - 单元测试:使用
static_assert验证 constexpr 结果,保证逻辑正确性。
结语
C++23 的协程和 constexpr 的改进,进一步提升了语言的表达力和性能。掌握这些特性后,开发者可以在项目中实现更高效、更易维护的代码。希望本文的示例和建议能帮助你快速上手,并在实际项目中获得收益。祝编码愉快!