有网友问我,C++的STL源码属于什么水平? 我也不知道,咱们来一起看看。

std::span 简介
我这里随手找了一个C++20 标准类型std::span
std::span 是一种“轻量、零拷贝的数组视图”,让你可以安全地操作一段连续内存,而不需要拷贝或持有数据。
我们一起来看看它的源码
span 类定义与继承
_EXPORT_STD template <class _Ty, size_t _Extent = dynamic_extent>
class span : private _Span_extent_type<_Ty, _Extent> {
这里dynamic_extent是一个 编译期常量标记
dynamic_extent 是一个常量,它的定义是这样的
_EXPORT_STD inline constexpr size_t dynamic_extent = static_cast<size_t>(-1);
因为我们知 道span 的核心特征之一 就是它既可以表示固定大小的数组视图,也可以表示运行时大小可变的数组视图。
所以这里的dynamic_extent用于表示 “运行时才知道的大小”
然后span类是私有继承_Span_extent_type类
从这里我们能学到,模板偏特化也就是根据模板参数的不同,生成不同的类定义,实现“条件化代码生成”
以及私有继承的使用
默认构造函数:C++20 特性集大成者
constexpr span() noexcept requires (_Extent == 0 || _Extent == dynamic_extent) = default;
这个是它的默认构造函数,别看短短一行,它几乎把 C++20 的语法精华全用上了
constexpr 表示这个构造函数可以在编译期求值
noexcept 用于保证不会抛出异常,这是现代C++的推荐做法,它的意思是构造函数只做“轻量、可保证成功”的初始化
requires (_Extent == 0 || _Extent == dynamic_extent) 这是 C++20 的约束表达式,它限定了这个构造函数只有当满足条件时才可用。
如果条件不成立,那么这个构造函数不会被实例化,这种写法叫作 约束性构造函数(Constrained Constructor),是 Concepts 最实用的应用之一
= default 的意思是让编译器自动生成默认实现。
看到没,这样一行代码就使用了这么多C++的特性,是不是可以学到好多C++知识,你们平时写代码会这样写吗?
带迭代器的构造函数
template <_Span_compatible_iterator<element_type> _It>
constexpr explicit(_Extent != dynamic_extent) span(_It _First, size_type _Count) noexcept // strengthened
: _Mybase(_STD to_address(_STD _Get_unwrapped_n(_First, _Count)), _Count) {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (_Extent != dynamic_extent) {
_STL_VERIFY(_Count == _Extent,
"Cannot construct span with static extent from range [first, first + count) as count != extent");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
这个构造函数_Span_compatible_iterator<element_type>是一个 concept
它是用来限制模板参数 _It 必须是能指向 element_type 类型,它取代了 C++17 的 std::enable_if 写法
所以你会发现每个版本的C++的STL源码都是紧跟新版本特性的
explicit(condition) 这是C++20新增语法,叫做条件显式构造,如果后边的条件 _Extent != dynamic_extent满足,那么构造函数就是显式的,否则,它是隐式的
数组引用的构造函数
template <size_t _Size>
requires (_Extent == dynamic_extent || _Extent == _Size)
constexpr span(type_identity_t<element_type> (&_Arr)[_Size]) noexcept : _Mybase(_Arr, _Size) {}
type_identity_t 是一个小技巧,它用来防止数组类型在模板参数推导时被“退化为指针”,如果没有它,那么这个 T(&)[N]就会被 推导成 T*,有了它就能 保留数组类型
兼容数组类型的构造函数
template <class _OtherTy, size_t _Size>
requires (_Extent == dynamic_extent || _Extent == _Size) && is_convertible_v<_OtherTy (*)[], element_type (*)[]>
constexpr span(array<_OtherTy, _Size>& _Arr) noexcept : _Mybase(_Arr.data(), _Size) {}
is_convertible_v 用于检查类型兼容性,只有当 _OtherTy[] 可以隐式转换成 element_type[] 时,才允许构造
是不是发现仅仅是构建函数,它就使用了这么多的C++特性,可能这些特性是我们平时碰都不敢碰的
first() 成员函数
template <size_t _Count>
_NODISCARD constexpr auto first() const noexcept /* strengthened */ {
if constexpr (_Extent != dynamic_extent) {
static_assert(_Count <= _Extent, "Count out of range in span::first()");
}
#if _CONTAINER_DEBUG_LEVEL > 0
else {
_STL_VERIFY(_Count <= _Mysize, "Count out of range in span::first()");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
return span<element_type, _Count>{_Mydata, _Count};
}
if constexpr 是C++17中的特性,用于编译期分支
它用于允许根据编译期常量条件选择分支,未被选中的分支不会被编译。
而static_assert 是编译期断言,它的错误信息会在编译时直接显示在IDE/编译器中,用于提早发现逻辑错误
subspan() 成员函数
template <size_t _Offset, size_t _Count = dynamic_extent>
_NODISCARD constexpr auto subspan() const noexcept /* strengthened */ {
if constexpr (_Extent != dynamic_extent) {
static_assert(_Offset <= _Extent, "Offset out of range in span::subspan()");
static_assert(
_Count == dynamic_extent || _Count <= _Extent - _Offset, "Count out of range in span::subspan()");
}
#if _CONTAINER_DEBUG_LEVEL > 0
else {
_STL_VERIFY(_Offset <= _Mysize, "Offset out of range in span::subspan()");
if constexpr (_Count != dynamic_extent) {
_STL_VERIFY(_Count <= _Mysize - _Offset, "Count out of range in span::subspan()");
}
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
using _ReturnType = span<element_type,
_Count != dynamic_extent ? _Count : (_Extent != dynamic_extent ? _Extent - _Offset : dynamic_extent)>;
return _ReturnType{_Mydata + _Offset, _Count == dynamic_extent ? _Mysize - _Offset : _Count};
}
这一行,使用 using 声明别名 + 编译期条件类型选择,根据不同模板参数组合计算返回 span 的类型,然后用三元表达式计算 _ReturnType 的 _Extent,实现自动推导
对了,前边的_NODISCARD是C++17的一个属性,它用来提示编译器:调用者不要忽略返回值。忽略返回值时会发出警告,它可以有效的防止潜在逻辑错误。
后边的代码中用到的特性就是刚才我们讲过的了,就不说了
std::span 的设计哲学
看过SPAN的代码后,会发现它的实现虽然看起来很朴素,但每一行都体现出 “零开销、安全可控、语义清晰” 这三大核心目标,它几乎不做任何多余的事,却完美体现了现代 C++ 的设计哲学
真的非常建议大家有空时看一看STL的源码,然后在你自己设计类的时候,可以用上它的这些技巧,你的设计水准一定蹭蹭的上涨
STL 源码的整体水平评价
STL作为 C++ 标准库的核心部分,其源码设计一直被誉为“艺术级”工程典范。
它不仅高效、通用,还体现了 C++ 语言演进的精髓:从模板元编程到现代特性无缝融合。
简单说,STL 源码水平高在“简洁却强大、零开销抽象、类型安全又高效”
它让抽象概念在编译期就优化到极致。 说它是C++修仙界的无上天道一点不为过。


