C++23是一个相对稳健的版本,专注于实用性改进和标准库的完善,体现了C++语言发展的成熟期特征:
- 错误处理现代化:std::expected提供函数式错误处理范式
- 多维计算支持:std::mdspan原生支持多维数组和科学计算
- 输出系统完善:std::print系列提供现代化的格式化输出
- Ranges生态完善:新增大量实用的视图和算法
- 开发体验优化:众多小而美的改进提升日常开发效率
#include <expected>
#include <string>
#include <system_error>
// 传统错误处理方式的问题
int divide_traditional(int a, int b, int& result) {
if (b == 0) return -1; // 错误代码含义不清晰
result = a / b;
return 0; // 成功
}
// C++17 std::optional的局限性
std::optional<int> divide_optional(int a, int b) {
if (b == 0) return std::nullopt; // 丢失了错误信息
return a / b;
}
// C++23 std::expected的优雅方案
std::expected<int, std::string> divide_expected(int a, int b) {
if (b == 0)
return std::unexpected("Division by zero");
return a / b;
}enum class MathError {
DivisionByZero,
NegativeSquareRoot,
Overflow
};
std::expected<double, MathError> safe_sqrt(double x) {
if (x < 0) return std::unexpected(MathError::NegativeSquareRoot);
return std::sqrt(x);
}
std::expected<double, MathError> safe_divide(double a, double b) {
if (b == 0.0) return std::unexpected(MathError::DivisionByZero);
return a / b;
}
// 错误传播的组合式处理
std::expected<double, MathError> complex_calculation(double a, double b, double c) {
return safe_divide(a, b)
.and_then([c](double result) { return safe_sqrt(result + c); })
.or_else([](MathError error) -> std::expected<double, MathError> {
// 错误恢复逻辑
switch (error) {
case MathError::DivisionByZero:
return 0.0; // 默认值
default:
return std::unexpected(error); // 传播错误
}
});
}// 基于异常的错误处理
class DivisionByZeroException : public std::exception {
const char* what() const noexcept override {
return "Division by zero";
}
};
double divide_exception(double a, double b) {
if (b == 0.0) throw DivisionByZeroException{};
return a / b;
}
// 基于expected的错误处理
std::expected<double, std::string> divide_expected_perf(double a, double b) {
if (b == 0.0) return std::unexpected("Division by zero");
return a / b;
}
// 性能测试对比
void performance_comparison() {
// expected的优势:
// 1. 零开销的正常路径执行
// 2. 无栈展开开销
// 3. 编译器优化友好
// 4. 缓存友好的内存布局
// 异常的劣势:
// 1. 栈展开的昂贵开销
// 2. 编译器优化困难
// 3. 代码大小膨胀
// 4. 异常安全代码的复杂性
}// 结构化错误信息
struct ValidationError {
std::string field_name;
std::string error_message;
std::source_location location;
ValidationError(std::string field, std::string msg,
std::source_location loc = std::source_location::current())
: field_name(std::move(field)), error_message(std::move(msg)), location(loc) {}
};
// 可组合的错误处理器
template<typename T, typename E>
class ResultChain {
std::expected<T, E> value_;
public:
explicit ResultChain(std::expected<T, E> value) : value_(std::move(value)) {}
template<typename F>
auto map(F&& func) -> ResultChain<decltype(func(std::declval<T>())), E> {
if (value_) {
return ResultChain<decltype(func(*value_)), E>{func(*value_)};
}
return ResultChain<decltype(func(std::declval<T>())), E>{std::unexpected(value_.error())};
}
template<typename F>
auto flat_map(F&& func) -> decltype(func(std::declval<T>())) {
if (value_) {
return func(*value_);
}
using ResultType = decltype(func(std::declval<T>()));
return ResultType{std::unexpected(value_.error())};
}
T value_or(T default_value) const {
return value_.value_or(std::move(default_value));
}
};#include <mdspan>
#include <vector>
#include <array>
// 传统多维数组的问题
void traditional_2d_array() {
// 1. C风格数组:大小固定,不安全
int matrix[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
// 2. vector<vector>:性能差,内存不连续
std::vector<std::vector<int>> matrix_vec(3, std::vector<int>(4));
// 3. 手动索引计算:容易出错
std::vector<int> flat_matrix(12);
auto get_element = [&](size_t row, size_t col) -> int& {
return flat_matrix[row * 4 + col]; // 手动计算索引
};
}
// C++23 std::mdspan的解决方案
void modern_mdspan_approach() {
// 连续内存存储
std::vector<int> data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
// 创建2D视图
std::mdspan<int, std::dextents<size_t, 2>> matrix(data.data(), 3, 4);
// 自然的多维索引
for (size_t i = 0; i < matrix.extent(0); ++i) {
for (size_t j = 0; j < matrix.extent(1); ++j) {
std::cout << matrix[i, j] << " "; // 直观的多维索引
}
std::cout << "\n";
}
}// 行主序布局(C/C++默认)
using row_major_2d = std::mdspan<double, std::dextents<size_t, 2>,
std::layout_right>;
// 列主序布局(Fortran风格)
using col_major_2d = std::mdspan<double, std::dextents<size_t, 2>,
std::layout_left>;
// 跨步布局(自定义步长)
using strided_2d = std::mdspan<double, std::dextents<size_t, 2>,
std::layout_stride>;
void layout_comparison() {
std::vector<double> data(12);
std::iota(data.begin(), data.end(), 1.0);
// 行主序:data[row * cols + col]
row_major_2d row_matrix(data.data(), 3, 4);
// 列主序:data[col * rows + row]
col_major_2d col_matrix(data.data(), 3, 4);
// 跨步布局:自定义访问模式
std::array<size_t, 2> extents{3, 4};
std::array<size_t, 2> strides{8, 2}; // 自定义步长
strided_2d strided_matrix(data.data(),
std::layout_stride::mapping{extents, strides});
}// 3D张量表示
template<typename T>
class Tensor3D {
std::vector<T> data_;
std::mdspan<T, std::dextents<size_t, 3>> view_;
public:
Tensor3D(size_t depth, size_t height, size_t width)
: data_(depth * height * width), view_(data_.data(), depth, height, width) {}
// 自然的3D索引访问
T& operator()(size_t d, size_t h, size_t w) {
return view_[d, h, w];
}
const T& operator()(size_t d, size_t h, size_t w) const {
return view_[d, h, w];
}
// 切片操作
auto slice(size_t depth_idx) {
return std::submdspan(view_, depth_idx, std::full_extent, std::full_extent);
}
// 张量运算
Tensor3D& operator+=(const Tensor3D& other) {
for (size_t d = 0; d < view_.extent(0); ++d) {
for (size_t h = 0; h < view_.extent(1); ++h) {
for (size_t w = 0; w < view_.extent(2); ++w) {
view_[d, h, w] += other.view_[d, h, w];
}
}
}
return *this;
}
};
// 矩阵乘法的mdspan实现
void matrix_multiply_mdspan(
std::mdspan<const double, std::dextents<size_t, 2>> A,
std::mdspan<const double, std::dextents<size_t, 2>> B,
std::mdspan<double, std::dextents<size_t, 2>> C
) {
assert(A.extent(1) == B.extent(0));
assert(C.extent(0) == A.extent(0));
assert(C.extent(1) == B.extent(1));
for (size_t i = 0; i < C.extent(0); ++i) {
for (size_t j = 0; j < C.extent(1); ++j) {
C[i, j] = 0;
for (size_t k = 0; k < A.extent(1); ++k) {
C[i, j] += A[i, k] * B[k, j];
}
}
}
}#include <print>
#include <format>
void output_system_evolution() {
// C语言时代:printf系列
printf("Hello %s, you are %d years old\n", "Alice", 25);
// C++早期:iostream
std::cout << "Hello " << "Alice" << ", you are " << 25 << " years old" << std::endl;
// C++20:std::format
std::cout << std::format("Hello {}, you are {} years old\n", "Alice", 25);
// C++23:std::print(最简洁)
std::print("Hello {}, you are {} years old\n", "Alice", 25);
std::println("Hello {}, you are {} years old", "Alice", 25); // 自动换行
}void unicode_output_demo() {
// 自动UTF-8输出
std::print("中文输出:{}\n", "你好世界");
std::print("Emoji: {} {}\n", "🌍", "🚀");
std::print("数学符号: ∑ ∫ ∞ π\n");
// 控制台兼容性
std::print("Console width: {}\n", 80);
// 错误输出到stderr
std::print(stderr, "Error: {}\n", "Something went wrong");
}void performance_optimized_output() {
// std::print的性能优势:
// 1. 直接系统调用,避免iostream的同步开销
// 2. 编译期格式字符串验证
// 3. 更少的虚函数调用
// 4. 更好的编译器优化机会
std::vector<int> large_data(1000000);
std::iota(large_data.begin(), large_data.end(), 1);
// 高效的批量输出
auto start = std::chrono::high_resolution_clock::now();
for (int value : large_data) {
std::print("{} ", value);
}
auto end = std::chrono::high_resolution_clock::now();
std::println("\nOutput time: {}ms",
std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count());
}#include <ranges>
#include <algorithm>
void new_views_demo() {
std::vector<int> data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// std::views::zip - 并行遍历多个范围
std::vector<char> letters{'a', 'b', 'c', 'd', 'e'};
for (auto [num, letter] : std::views::zip(data, letters)) {
std::print("{}: {}\n", num, letter);
}
// std::views::zip_transform - 变换后的zip
auto products = std::views::zip_transform(std::multiplies{}, data, data);
for (int square : products | std::views::take(5)) {
std::print("{} ", square); // 1 4 9 16 25
}
std::println("");
// std::views::adjacent - 相邻元素处理
auto differences = data | std::views::adjacent<2>
| std::views::transform([](auto pair) {
auto [a, b] = pair;
return b - a;
});
// std::views::adjacent_transform - 直接变换相邻元素
auto adjacent_sums = data | std::views::adjacent_transform<2>(std::plus{});
// std::views::chunk - 分块处理
for (auto chunk : data | std::views::chunk(3)) {
std::print("Chunk: ");
for (int val : chunk) {
std::print("{} ", val);
}
std::println("");
}
// std::views::slide - 滑动窗口
auto sliding_windows = data | std::views::slide(3);
for (auto window : sliding_windows) {
std::print("Window: ");
for (int val : window) {
std::print("{} ", val);
}
std::println("");
}
}void enhanced_range_algorithms() {
std::vector<int> data{3, 1, 4, 1, 5, 9, 2, 6};
// std::ranges::to - 范围到容器的转换
auto filtered = data
| std::views::filter([](int x) { return x > 3; })
| std::ranges::to<std::vector>();
auto set_result = data
| std::views::filter([](int x) { return x % 2 == 0; })
| std::ranges::to<std::set>();
// 链式转换
auto processed = data
| std::views::transform([](int x) { return x * 2; })
| std::views::filter([](int x) { return x > 5; })
| std::ranges::to<std::deque>();
// std::ranges::contains - 包含检查
bool has_five = std::ranges::contains(data, 5);
std::println("Contains 5: {}", has_five);
// std::ranges::starts_with / ends_with
std::vector<int> prefix{3, 1};
bool starts_with_prefix = std::ranges::starts_with(data, prefix);
// std::ranges::find_last - 从后往前查找
auto last_1 = std::ranges::find_last(data, 1);
if (last_1 != data.end()) {
std::println("Last 1 found at position: {}",
std::distance(data.begin(), last_1));
}
}// 自定义一个"重复"视图适配器
template<std::ranges::view V>
class repeat_view : public std::ranges::view_interface<repeat_view<V>> {
private:
V base_;
size_t count_;
public:
repeat_view(V base, size_t count) : base_(std::move(base)), count_(count) {}
class iterator {
std::ranges::iterator_t<V> iter_;
std::ranges::iterator_t<V> begin_;
std::ranges::iterator_t<V> end_;
size_t current_repeat_;
size_t max_repeats_;
public:
using value_type = std::ranges::range_value_t<V>;
using difference_type = std::ptrdiff_t;
iterator(std::ranges::iterator_t<V> begin, std::ranges::iterator_t<V> end,
size_t max_repeats)
: iter_(begin), begin_(begin), end_(end),
current_repeat_(0), max_repeats_(max_repeats) {}
auto operator*() const { return *iter_; }
iterator& operator++() {
++iter_;
if (iter_ == end_ && current_repeat_ < max_repeats_ - 1) {
iter_ = begin_;
++current_repeat_;
}
return *this;
}
bool operator==(const iterator& other) const {
return iter_ == other.iter_ && current_repeat_ == other.current_repeat_;
}
};
iterator begin() { return iterator{std::ranges::begin(base_), std::ranges::end(base_), count_}; }
iterator end() {
auto end_iter = iterator{std::ranges::end(base_), std::ranges::end(base_), count_};
return end_iter;
}
};
// 创建自定义视图的便利函数
template<std::ranges::view V>
repeat_view<V> repeat(V&& view, size_t count) {
return repeat_view<V>{std::forward<V>(view), count};
}#include <type_traits>
// 运行时和编译期的不同行为
constexpr int flexible_function(int x) {
if consteval {
// 编译期执行的代码
return x * x; // 简单计算
} else {
// 运行时执行的代码
return expensive_runtime_calculation(x); // 复杂计算
}
}
// 编译期优化的实际应用
template<typename T>
constexpr auto safe_cast(auto value) {
if consteval {
// 编译期:直接转换,编译器会检查安全性
return static_cast<T>(value);
} else {
// 运行时:添加额外检查
if (value < std::numeric_limits<T>::min() ||
value > std::numeric_limits<T>::max()) {
throw std::overflow_error("Cast overflow");
}
return static_cast<T>(value);
}
}#include <utility>
// 编译器优化提示
int optimized_switch(int value) {
switch (value) {
case 1: return 10;
case 2: return 20;
case 3: return 30;
default:
// 告诉编译器这里永远不会执行
std::unreachable();
}
// 编译器可以优化掉后续的死代码
}
// 性能关键路径的优化
template<int N>
constexpr int factorial() {
if constexpr (N == 0 || N == 1) {
return 1;
} else if constexpr (N > 1 && N <= 20) {
return N * factorial<N-1>();
} else {
// 编译期就能确定这种情况不会发生
std::unreachable();
}
}#include <type_traits>
#include <concepts>
// 新的类型特征
template<typename T>
void type_traits_demo() {
// std::is_scoped_enum - 检测作用域枚举
enum class Color { Red, Green, Blue };
enum OldColor { RED, GREEN, BLUE };
static_assert(std::is_scoped_enum_v<Color>); // true
static_assert(!std::is_scoped_enum_v<OldColor>); // false
// std::is_implicit_lifetime - 检测隐式生命周期类型
static_assert(std::is_implicit_lifetime_v<int>);
// std::reference_constructs_from_temporary
static_assert(std::reference_constructs_from_temporary_v<const std::string&, const char*>);
}
// 新的标准概念
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
template<typename R>
concept ContiguousRange = std::ranges::contiguous_range<R> &&
std::ranges::sized_range<R>;
// 增强的concept使用
template<ContiguousRange R>
requires Numeric<std::ranges::range_value_t<R>>
auto sum_contiguous(R&& range) {
using ValueType = std::ranges::range_value_t<R>;
return std::accumulate(std::ranges::begin(range),
std::ranges::end(range),
ValueType{});
}void container_improvements() {
// std::flat_map和std::flat_set(提案中)
// 基于排序vector的关联容器,更好的缓存局部性
// std::stacktrace(部分实现)
// 程序崩溃时的调用栈追踪
// 改进的hash支持
std::unordered_map<std::string, int> map;
map["key"] = 42;
// 透明哈希查找
auto it = map.find("key"); // 避免不必要的string构造
}C++23体现了C++语言发展的四个重要方向:
- std::expected解决了实际项目中的错误处理痛点
- std::print提供了简洁高效的输出方案
- ranges改进完善了函数式编程生态
- std::mdspan零开销的多维数组抽象
- if consteval编译期运行期分离优化
- std::unreachable帮助编译器生成更优代码
- ranges生态系统的进一步扩展
- 新的类型特征支持更精确的类型检查
- 容器改进提升日常使用体验
- 保持与现有代码的兼容性
- 提供更现代的替代方案
- 渐进式迁移路径
C++23虽然没有C++11和C++20那样的革命性变化,但通过大量实用的改进,显著提升了C++的开发体验和代码质量。这些特性的组合使用将进一步巩固C++在系统编程、高性能计算和现代应用开发中的地位。