std::span

来自cppreference.com
< cpp‎ | container
定义于头文件 <span>
template<

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

> class span;
(C++20 起)

类模板 span 所描述的对象能指代对象的相接序列,序列的首元素在零位置。 span 能拥有静态长度,该情况下序列中的元素数已知并编码于类型中,或拥有动态长度。

典型实现只保有两个成员:指向 T 的指针和大小。

模板形参

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
(公开成员函数)
迭代器
返回指向起始的迭代器
(公开成员函数)
返回指向末尾的迭代器
(公开成员函数)
返回指向起始的逆向迭代器
(公开成员函数)
返回指向末尾的逆向迭代器
(公开成员函数)
元素访问
访问第一个元素
(公开成员函数)
访问最后一个元素
(公开成员函数)
访问序列的元素
(公开成员函数)
返回指向元素序列起始的指针
(公开成员函数)
观察器
返回序列中的元素数
(公开成员函数)
返回以字节表示的序列大小
(公开成员函数)
检查序列是否为空
(公开成员函数)
子视图
获得由序列首 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>> =

    Extent == 0 || Extent == dynamic_extent;

std::ranges::enable_view 的此特化使零或动态长度的 span 满足 view 。非零静态长度的 span 非 default_initializable 从而不是视图。

推导指引

示例

示例用 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(data.begin(), data.end(), prefix.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();
}
 
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