4. ArrayView

除了我们自己需要明确定义和管理的数组之外,还有另外一族数组,它们属于已经定义好的 POD 数据 结构中所包含的数组。

一个可以做出的假设是,由于这些数组都是 POD 的,因而必然是平凡的。

但是,为了操作的方便性,我们往往又会为这些 POD 数组加上一层 wrapper ,让它们可以在 不增加任何开销的情况下,变为逻辑功能更加内聚的对象。

这些数组,根据是从外而来的消息,还是由内往外的消息,又可以分为只读和可写的。

结合这些需求,需要定义如下两种 ArrayView :(之所以被称做 view ,是因为 view 本身并不 拥有数据,它只是查看或操作别人持有的数据。

4.1. ConstArrayView

template <typename OBJ, std::size_t MAX_NUM, typename ELEM = OBJ>
struct ConstArrayView {
   using SizeType = DeduceSizeType_T<MAX_NUM>;
   using ElemType = ELEM;
   using ViewTrait = typename ArrayViewTrait<OBJ, ELEM>::Type;

   ConstArrayView(OBJ const* array, std::size_t n)
      : elems(ViewTrait::ConstObjToElem(array))
      , num(std::min(MAX_NUM, n))
   {}

   ElemType const* elems;
   SizeType num;
};

4.2. ArrayView

template <typename OBJ, typename SIZE_TYPE, SIZE_TYPE MAX_NUM, typename ELEM = OBJ>
struct ArrayView {
   using ElemType = ELEM;
   using ViewTrait = typename ArrayViewTrait<OBJ, ELEM>::Type;

   ArrayView(OBJ* array, SIZE_TYPE& n)
      : elems(ViewTrait::ObjToElem(array))
      , num(n)
   {}

   ElemType* elems;
   SIZE_TYPE& num;
};

4.3. 自动识别

除非你明确定义,否则,你不会直接使用 ConstArrayView 。 你只需要使用 ArrayView ,然后依靠模版类的自动类型推演来自动决定。比如:

struct Foo {
   int array[10];
   uint16_t num;
};

Foo foo{{1,2,3,4}, 4};

ArrayView view1{foo.array, foo.num}; // ArrayView

view1.Append(5); // so you can append

Foo const& constRef = foo;

ArrayView view2{foo.array, foo.num}; // ConstArrayView

view2.Append(5); // compiling error.

ArrayView<T,N> 可以使用 ObjectArray<T, N> 的一切接口和算法。