C++23 标准库新增内容全面解析
1. 引言
C++23 是 C++20 之后的一个重要标准更新,虽然不像 C++11 或 C++20 那样带来颠覆性的变化,但在标准库方面仍然提供了许多实用的新功能和改进。这些新增内容主要集中在简化常见任务、填补功能空白、提升性能以及增强类型安全等方面。本文将详细介绍 C++23 标准库的主要新增内容,并通过代码示例展示其用法。
2. 容器与算法增强
2.1 std::flat_map 和 std::flat_set
C++23 引入了两个新的关联容器:std::flat_map和std::flat_set。它们基于排序的向量实现,提供了比传统红黑树实现的std::map和std::set更好的缓存局部性和内存效率,但插入和删除操作可能更慢。
#include <flat_map> #include <iostream> int main() { std::flat_map<std::string, int> scores; // 插入元素 scores.insert({"Alice", 95}); scores.insert({"Bob", 87}); scores.insert_or_assign("Charlie", 92); // 范围for遍历(按键排序) for (const auto& [name, score] : scores) { std::cout << name << ": " << score << '\n'; } // 查找操作 if (auto it = scores.find("Alice"); it != scores.end()) { std::cout << "Found Alice: " << it->second << '\n'; } return 0; }2.2 std::mdspan - 多维数组视图
std::mdspan是一个非拥有型多维数组视图,类似于一维的std::span,但支持任意维度。它对于科学计算、图像处理和数值模拟等场景非常有用。
#include <mdspan> #include <vector> #include <iostream> int main() { std::vector<int> data(12); std::iota(data.begin(), data.end(), 1); // 填充1-12 // 创建3x4的二维视图 std::mdspan mat(data.data(), 3, 4); // 访问元素 std::cout << "Element at (1,2): " << mat[1, 2] << '\n'; // 遍历所有元素 for (std::size_t i = 0; i < mat.extent(0); ++i) { for (std::size_t j = 0; j < mat.extent(1); ++j) { std::cout << mat[i, j] << ' '; } std::cout << '\n'; } return 0; }2.3 新的算法:std::shift_left 和 std::shift_right
这两个算法将元素向左或向右移动指定位置,移出范围的元素被丢弃,空出的位置用默认值填充。
#include <algorithm> #include <vector> #include <iostream> int main() { std::vector<int> v = {1, 2, 3, 4, 5}; // 向左移动2位 auto new_end = std::shift_left(v.begin(), v.end(), 2); // v现在为: {3, 4, 5, ?, ?},?表示未指定值 std::cout << "After shift_left by 2: "; for (int i = 0; i < 3; ++i) std::cout << v[i] << ' '; std::cout << '\n'; // 向右移动1位 std::shift_right(v.begin(), v.end(), 1); // v现在为: {?, 3, 4, 5, ?} return 0; }3. 字符串与文本处理
3.1 std::basic_string::contains()
为std::string和std::string_view添加了contains()成员函数,用于检查字符串是否包含子串,比使用find() != npos更直观。
#include <string> #include <iostream> int main() { std::string str = "Hello, C++23 World!"; // 检查是否包含子串 if (str.contains("C++23")) { std::cout << "String contains 'C++23'\n"; } if (str.contains('W')) { std::cout << "String contains character 'W'\n"; } // 也适用于string_view std::string_view sv = str; if (sv.contains("World")) { std::cout << "String view contains 'World'\n"; } return 0; }3.2 std::format 增强
C++23 对std::format进行了多项改进,包括支持范围格式化、改进的 Unicode 处理等。
#include <format> #include <vector> #include <iostream> int main() { // 范围格式化 std::vector<int> nums = {1, 2, 3, 4, 5}; std::cout << std::format("Numbers: {:n}\n", nums); // 输出: Numbers: 1, 2, 3, 4, 5 // 改进的浮点数格式化 double pi = 3.141592653589793; std::cout << std::format("Pi: {:.5f}\n", pi); std::cout << std::format("Pi in scientific: {:.5e}\n", pi); // 嵌套格式化 std::cout << std::format("Vector: {}\n", std::format("{}", nums)); return 0; }4. 工具类型与元编程
4.1 std::expected - 期望类型
std::expected<T, E>表示一个可能包含值T或错误E的类型,类似于 Rust 的Result类型,提供了一种类型安全的错误处理方式。
#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; } int main() { auto result1 = divide(10, 2); if (result1) { std::cout << "Result: " << *result1 << '\n'; } auto result2 = divide(10, 0); if (!result2) { std::cout << "Error: " << result2.error() << '\n'; } // 使用value_or提供默认值 int val = divide(5, 0).value_or(-1); std::cout << "Value or default: " << val << '\n'; return 0; }4.2 std::optional 和 std::variant 的 monadic 操作
C++23 为std::optional和std::variant添加了函数式编程风格的操作,如and_then()、or_else()、transform()等。
#include <optional> #include <string> #include <iostream> std::optional<int> parse_int(const std::string& s) { try { return std::stoi(s); } catch (...) { return std::nullopt; } } std::optional<std::string> to_hex(int n) { if (n < 0) return std::nullopt; char buffer[20]; sprintf(buffer, "%X", n); return buffer; } int main() { std::optional<std::string> input = "255"; // 链式操作:解析字符串 -> 转换为十六进制 auto result = input .and_then(parse_int) // 如果input有值,尝试解析为int .and_then(to_hex) // 如果解析成功,转换为十六进制 .transform([](const std::string& s) { return "0x" + s; // 添加前缀 }) .value_or("Invalid input"); std::cout << "Result: " << result << '\n'; return 0; }5. 并发与异步
5.1 std::generator - 协程生成器
std::generator是一个用于协程的生成器类型,可以方便地创建惰性序列。
#include <generator> #include <iostream> #include <ranges> std::generator<int> fibonacci(int n) { int a = 0, b = 1; for (int i = 0; i < n; ++i) { co_yield a; int temp = a + b; a = b; b = temp; } } int main() { // 生成前10个斐波那契数 for (int num : fibonacci(10)) { std::cout << num << ' '; } std::cout << '\n'; // 与ranges结合使用 auto even_fib = fibonacci(15) | std::views::filter([](int n) { return n % 2 == 0; }); std::cout << "Even Fibonacci numbers: "; for (int num : even_fib) { std::cout << num << ' '; } std::cout << '\n'; return 0; }5.2 std::atomic_ref 增强
C++23 扩展了std::atomic_ref的功能,支持更多类型和操作。
#include <atomic> #include <thread> #include <iostream> #include <vector> struct Point { double x, y; // 需要提供默认构造函数 Point() = default; Point(double x, double y) : x(x), y(y) {} }; int main() { Point p{1.0, 2.0}; std::atomic_ref<Point> atomic_p{p}; // 原子地更新整个结构体 Point new_point{3.0, 4.0}; atomic_p.store(new_point); // 原子地读取 Point current = atomic_p.load(); std::cout << "Current point: (" << current.x << ", " << current.y << ")\n"; // 比较交换操作 Point expected{3.0, 4.0}; Point desired{5.0, 6.0}; if (atomic_p.compare_exchange_strong(expected, desired)) { std::cout << "CAS succeeded\n"; } return 0; }6. 其他重要新增
6.1 栈踪库 std::stacktrace
std::stacktrace提供了获取当前调用栈信息的能力,对于调试和错误报告非常有用。
#include <stacktrace> #include <iostream> void func_c() { auto trace = std::stacktrace::current(); std::cout << "Stack trace from func_c:\n"; for (const auto& entry : trace) { std::cout << " " << entry.description() << '\n'; } } void func_b() { func_c(); } void func_a() { func_b(); } int main() { func_a(); return 0; }6.2 类型特征增强
C++23 添加了新的类型特征,如std::is_scoped_enum、std::to_underlying等。
#include <type_traits> #include <iostream> enum class Color { Red, Green, Blue }; enum OldColor { Red, Green, Blue }; int main() { // 检查是否为有作用域的枚举 std::cout << std::boolalpha; std::cout << "Color is scoped enum: " << std::is_scoped_enum_v<Color> << '\n'; std::cout << "OldColor is scoped enum: " << std::is_scoped_enum_v<OldColor> << '\n'; // 获取枚举的基础类型值 Color c = Color::Green; auto underlying = std::to_underlying(c); std::cout << "Underlying value of Color::Green: " << underlying << '\n'; return 0; }6.3 数学常量
在<numbers>头文件中添加了更多数学常量。
#include <numbers> #include <iostream> int main() { using std::numbers; std::cout << "Pi: " << numbers::pi << '\n'; std::cout << "Euler's number: " << numbers::e << '\n'; std::cout << "Golden ratio: " << numbers::phi << '\n'; std::cout << "sqrt(2): " << numbers::sqrt2 << '\n'; std::cout << "ln(2): " << numbers::ln2 << '\n'; return 0; }7. 总结
C++23 标准库的新增内容虽然不如 C++20 那样庞大,但提供了许多实用的改进和新功能:
- 新容器:
std::flat_map、std::flat_set提供了性能与内存的平衡选择 - 多维数组:
std::mdspan简化了多维数据处理 - 字符串增强:
contains()方法使子串检查更直观 - 错误处理:
std::expected提供了类型安全的错误处理机制 - 函数式编程:
std::optional和std::variant的 monadic 操作 - 协程支持:
std::generator简化了惰性序列生成 - 调试工具:
std::stacktrace提供了调用栈追踪能力
这些新增功能使 C++ 在现代编程中更加易用、安全和高效。建议开发者根据项目需求逐步采用这些新特性,特别是std::expected和std::f
