C++ 缺少一个简单的“查看连续的内存块”类。这是一个:
template<class T>
struct ro_array_view {
T const* b_ = nullptr;
T const* e_ = nullptr;
size_t size() const { return end()-begin(); }
T const* begin() const { return b_; }
T const* end() const { return e_; }
T const& operator[](size_t i)const{ return begin()[i]; }
bool empty()const{return begin()==end();}
T const& front() const { return *begin(); }
T const& back() const { return *std::prev(end()); }
// annoying numbers of constructors:
struct from_container_tag {};
template<class O>
ro_array_view( from_container_tag, O&& o ):
ro_array_view(o.data(), o.size()) {}
template<class...A>
ro_array_view( std::vector<T,A...> const& o )
:ro_array_view(from_container_tag{},o) {}
ro_array_view( std::initializer_list<T> const& il )
:ro_array_view(il.begin(), il.size()) {}
template<size_t N>
ro_array_view( std::array<T, N> const& o )
:ro_array_view(from_container_tag{},o) {}
template<size_t N>
ro_array_view( std::array<T const, N> const& o )
:ro_array_view(from_container_tag{},o) {}
template<size_t N>
ro_array_view( T const(&arr)[N] )
:array_view( arr, N ) {}
// penultimate constructor of most paths:
ro_array_view( T const* arr, size_t N )
:ro_array_view(arr, arr+N) {}
// terminal constructor:
ro_array_view( T const* b, T const* e )
:b_(b),e_(e) {}
};
现在只需使用ro_array_view<int>,它就会将传入的参数转换为一对指针,并向其公开一个只读的类似容器的接口。
乍一看这似乎有点过头了,但你会发现它是一个非常常用的函数。大量采用 std::vector<T> const& 的函数应该按值采用 ro_array_view<T>。
非ro_array_view 有点不同(它的方法大多仍然是const,但它存储T* 而不是T const*。我称之为rw_array_view,然后将array_view a using 有条件地使用 ro_array_view 或 rw_array_view 的别名。添加从 rw_array_view 到 ro_array_view 的转换 ctor 以完成项目。
我有两种不同的类型,而不是一种,因为rw_array_view 和ro_array_view 具有来自某些容器的不同构造函数。 rw_array_view<T> 可以从 vector<T,A...>& 构造,而 ro_array_view<T> 需要 vector<T, A...>const&。 std::array 有点糟糕,因为const T 是std::array 中的有效类型。 ro_array_view 用于大多数用途,rw_array_view 适用于我们想要修改内容而不修改容器的情况。