C++20 span
C++20 span
概念
std::span<T, Extent>
类模板就是一块连续内存的视图(类似于 std::string_view
),简化原本C风格的基制指针+长度的使用方式。
模板形参:
T
:元素类型;必须是完整对象类型且非抽象类Extent
:连续序列中的元素数,默认为动态长度(std::dynamic_extent
)
注意:
-
span
能拥有静态 长度,此时序列中的元素数在编译期已知并在类型中编码,也可以拥有动态 长度。 -
对于
span s
,当有操作使得范围[s.data(), s.data() + s.size())
中的指针失效时,到 s 的元素的指针、迭代器和引用也会失效。这种情况对应于使用span
来观察如vector
这样的容器时。
实现一个简易的span
#include <iostream>
#include <array>
#include <vector>
#include <type_traits>
template<typename T>
class Span
{
public:
constexpr Span(T* arr, size_t n) : m_data(arr), m_size(n) {} // 单纯的指针
template<size_t N>
constexpr Span(T (&arr)[N]) : m_data(arr), m_size(N) {} // 原生数组
template<size_t N>
constexpr Span(std::array<T, N>& arr) : m_data(arr.data()), m_size(N) {} // 数组容器
// 其他具有老式连续迭代器的容器
constexpr Span(std::vector<T>& arr) : m_data(arr.data()), m_size(arr.size()) {
static_assert(!std::is_same<T, bool>::value, "std::vector<bool> does't have contiguous iterator!");
}
constexpr T* data() const { return m_data; }
constexpr size_t size() const { return m_size; }
constexpr T& operator[](size_t i) const { return *(m_data + i); }
constexpr T& front() const { return m_data[0]; }
constexpr T& back() const { return m_data[m_size - 1]; }
constexpr Span<T> subSpan(size_t offset) const {
return Span<T>(m_data + offset, m_size - offset);
}
constexpr Span<T> first(size_t n) const {
return subSpan(0, n);
}
constexpr Span<T> last(size_t n) const {
return subSpan(m_size - n);
}
private:
T* m_data;
size_t m_size;
};
template<typename T>
inline constexpr Span<T> make_span(T* arr, size_t n) {
return Span<T>(arr, n);
}
void zero(Span<char> sp){
std::fill(sp.data(), sp.data() + sp.size(), 0);
}
int main()
{
char aa[11] = "abcdefghij";
std::array<char, 11> bb = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
std::vector<char> cc = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
size_t n = 11;
char* pc = new char[n];
zero(bb);
zero(cc);
zero(make_span(pc, n));
zero({pc, n});
std::cout << aa << std::endl << bb.data()<< std::endl;
Span<char> sp(aa);
auto ssp = sp.subSpan(4);
std::cout << aa << std::endl << ssp.data()<< std::endl;
zero(ssp);
std::cout << aa << std::endl << ssp.data()<< std::endl;
delete[] pc;
}