std::span

来自cppreference.com
< cpp‎ | container
在标头 <span> 定义
template<

    class T,
    std::size_t Extent = std::dynamic_extent

> class span;
(C++20 起)

类模板 span 所描述的对象可以指代首元素在零位置的连续序列。 span 能拥有静态长度,该情况下序列中的元素数已知并在编译期以模版参数 Extent 指定,否则默认拥有动态长度。

如果span动态长度,那它的典型实现会有两个成员:指向 T 的指针和长度。如果是静态长度可能只有一个成员:指向 T 的指针。

std::span 的每个特化均为可平凡复制 (TriviallyCopyable) 类型。

(C++23 起)

模板形参

T - 元素类型;必须是完整对象类型且非抽象类
Extent - 序列中的元素数,或若它为动态则为 std::dynamic_extent

成员类型

成员类型 定义
element_type T
value_type std::remove_cv_t<T>
size_type std::size_t
difference_type std::ptrdiff_t
pointer T*
const_pointer const T*
reference T&
const_reference const T&
iterator 实现定义的老式随机访问迭代器 (LegacyRandomAccessIterator) 常量表达式迭代器 (ConstexprIterator) 老式连续迭代器 (LegacyContiguousIterator) ,其 value_typevalue_type
reverse_iterator std::reverse_iterator<iterator>
const_reverse_iterator std::reverse_iterator<const_iterator>

注意:若 T 无 const 限定则 iterator 为可变迭代器。

容器 (Container) 的迭代器类型上的所有要求亦应用于 spaniterator 类型。

成员常量

static constexpr std::size_t extent = Extent;

成员函数

构造 span
(公开成员函数)
赋值 span
(公开成员函数)
迭代器
(C++20)
返回指向起始的迭代器
(公开成员函数)
(C++20)
返回指向末尾的迭代器
(公开成员函数)
(C++20)
返回指向起始的逆向迭代器
(公开成员函数)
(C++20)
返回指向末尾的逆向迭代器
(公开成员函数)
元素访问
(C++20)
访问第一个元素
(公开成员函数)
(C++20)
访问最后一个元素
(公开成员函数)
访问序列的元素
(公开成员函数)
返回指向元素序列起始的指针
(公开成员函数)
观察器
返回序列中的元素数
(公开成员函数)
返回以字节表示的序列大小
(公开成员函数)
检查序列是否为空
(公开成员函数)
子视图
获得由序列首 N 个元素组成的子段
(公开成员函数)
获得由序列末 N 个元素组成的子段
(公开成员函数)
获得子段
(公开成员函数)

非成员函数

转换 span 为对其底层字节的视图
(函数模板)

非成员常量

size_t 类型常量,指明 span 拥有动态长度
(常量)

辅助模板

template<class T, std::size_t Extent>
inline constexpr bool ranges::enable_borrowed_range<std::span<T, Extent>> = true;

std::ranges::enable_borrowed_range 的此特化使得 span 满足 borrowed_range

template<class T, std::size_t Extent>
inline constexpr bool ranges::enable_view<std::span<T, Extent>> = true;

std::ranges::enable_view 的此特化使零或动态长度的 span 满足 view

推导指引

注解

即使在 C++23 中引入的正式要求前,所有既存实现中 std::span 的特化已经为可平凡复制类型。

功能特性测试 标准 备注
__cpp_lib_span 202002L (C++20) std::span

示例

示例用 std::span 实现连续范围上的算法。

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <span>
 
template<class T, std::size_t N> [[nodiscard]]
constexpr auto slide(std::span<T,N> s, std::size_t offset, std::size_t width) {
    return s.subspan(offset, offset + width <= s.size() ? width : 0U);
}
 
template<class T, std::size_t N, std::size_t M> [[nodiscard]]
constexpr bool starts_with(std::span<T,N> data, std::span<T,M> prefix) {
    return data.size() >= prefix.size() 
        && std::equal(prefix.begin(), prefix.end(), data.begin());
}
 
template<class T, std::size_t N, std::size_t M> [[nodiscard]]
constexpr bool ends_with(std::span<T,N> data, std::span<T,M> suffix) {
    return data.size() >= suffix.size() 
        && std::equal(data.end() - suffix.size(), data.end(), 
                      suffix.end() - suffix.size());
}
 
template<class T, std::size_t N, std::size_t M> [[nodiscard]]
constexpr bool contains(std::span<T,N> span, std::span<T,M> sub) {
    return std::search(span.begin(), span.end(), sub.begin(), sub.end()) != span.end();
//  return std::ranges::search(span, sub).begin() != span.end();
}
 
void print(const auto& seq) {
    for (const auto& elem : seq) std::cout << elem << ' ';
    std::cout << '\n';
}
 
int main()
{
    constexpr int a[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
    constexpr int b[] { 8, 7, 6 };
 
    for (std::size_t offset{}; ; ++offset) {
        constexpr std::size_t width{6};
        auto s = slide(std::span{a}, offset, width);
        if (s.empty())
            break;
        print(s);
    }
 
    static_assert(starts_with(std::span{a}, std::span{a,4})
        && starts_with(std::span{a+1, 4}, std::span{a+1,3})
        && !starts_with(std::span{a}, std::span{b})
        && !starts_with(std::span{a,8}, std::span{a+1,3})
        && ends_with(std::span{a}, std::span{a+6,3})
        && !ends_with(std::span{a}, std::span{a+6,2})
        && contains(std::span{a}, std::span{a+1,4})
        && !contains(std::span{a,8}, std::span{a,9}));
}

输出:

0 1 2 3 4 5 
1 2 3 4 5 6 
2 3 4 5 6 7 
3 4 5 6 7 8

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
P2325R3 C++20 非零静态长度的 span 不是 view view 不要求 default_initializable 故它们是

参阅

列表初始化中创建临时数组然后引用它
(类模板)
只读的字符串视图
(类模板)
将迭代器/哨位对结合为一个 view
(类模板)