概述
C++26为std::span带来了四项针对性改进,使其成为标准库中更完整和一致的工具。
1. P2447R6: std::span支持初始化列表
之前,将花括号初始化列表(如{1, 2, 3})传递给span函数参数会失败,需要双层花括号。
void take(std::span<const int> v);
take({1, 2, 3}); // C++26之前:错误
take({1, 2, 3}); // C++26:正常工作
2. P2821R5: span.at()
这是最简单的补充——可以说是std::span一开始就应有的功能。它为span添加了边界检查的查找。
其他所有连续容器和视图(std::string、std::string_view、std::vector、std::array、std::deque)都同时提供不安全的operator[]和安全抛出异常的at(),span是唯一的例外。
std::array<int, 4> arr = {1, 2, 3, 4};
std::span<int> s{arr};
s[10]; // 未定义行为
s.at(10); // 抛出 std::out_of_range
3. P2833R2: Freestanding Library支持span
将span(以及expected、out_ptr、inout_ptr、mdspan)添加到freestanding实现中。这些功能可以在嵌入式系统、内核或裸金属环境中使用。
注意:由于freestanding环境通常不支持异常,span::at()被排除在freestanding子集之外。
4. P3029R1: 更好的mdspan CTAD
改进类模板参数推导(CTAD),保留编译时大小信息。
int arr[5] = {1, 2, 3, 4, 5};
int* p = arr;
// C++26之前:推导为 span<int, dynamic_extent>
std::span s1(p, std::integral_constant<std::size_t, 5>{});
// C++26:推导为 span<int, 5>
std::span s2(p, std::integral_constant<std::size_t, 5>{});
总结
C++26为span及其生态系统带来了四项针对性改进:
- 通过新的initializer_list构造函数实现更人体工程学的初始化
- 迟到已久的at()用于边界检查访问
- 在freestanding环境中支持span
- 更智能的CTAD,保留编译时大小信息
这些都不是突破性的变化,但它们消除了粗糙边缘,使span成为标准库中更完整和一致的工具。