刪除到 T 的連續緩衝區

並非所有型別擦除都涉及虛擬繼承,分配,放置新的,甚至是函式指標。

型別擦除型別擦除的原因是它描述了一組(一組)行為,並採用支援該行為並將其包裝起來的任何型別。不在該組行為中的所有資訊都被遺忘刪除

array_view 獲取其傳入範圍或容器型別並刪除所有內容,除了它是 T 的連續緩衝區。

// helper traits for SFINAE:
template<class T>
using data_t = decltype( std::declval<T>().data() );

template<class Src, class T>
using compatible_data = std::integral_constant<bool, std::is_same< data_t<Src>, T* >{} || std::is_same< data_t<Src>, std::remove_const_t<T>* >{}>;

template<class T>
struct array_view {
  // the core of the class:
  T* b=nullptr;
  T* e=nullptr;
  T* begin() const { return b; }
  T* end() const { return e; }

  // provide the expected methods of a good contiguous range:
  T* data() const { return begin(); }
  bool empty() const { return begin()==end(); }
  std::size_t size() const { return end()-begin(); }

  T& operator[](std::size_t i)const{ return begin()[i]; }
  T& front()const{ return *begin(); }
  T& back()const{ return *(end()-1); }

  // useful helpers that let you generate other ranges from this one
  // quickly and safely:
  array_view without_front( std::size_t i=1 ) const {
    i = (std::min)(i, size());
    return {begin()+i, end()};
  }
  array_view without_back( std::size_t i=1 ) const {
    i = (std::min)(i, size());
    return {begin(), end()-i};
  }

  // array_view is plain old data, so default copy:
  array_view(array_view const&)=default;
  // generates a null, empty range:
  array_view()=default;

  // final constructor:
  array_view(T* s, T* f):b(s),e(f) {}
  // start and length is useful in my experience:
  array_view(T* s, std::size_t length):array_view(s, s+length) {}

  // SFINAE constructor that takes any .data() supporting container
  // or other range in one fell swoop:
  template<class Src,
    std::enable_if_t< compatible_data<std::remove_reference_t<Src>&, T >{}, int>* =nullptr,
    std::enable_if_t< !std::is_same<std::decay_t<Src>, array_view >{}, int>* =nullptr
  >
  array_view( Src&& src ):
    array_view( src.data(), src.size() )
  {}

  // array constructor:
  template<std::size_t N>
  array_view( T(&arr)[N] ):array_view(arr, N) {}

  // initializer list, allowing {} based:
  template<class U,
    std::enable_if_t< std::is_same<const U, T>{}, int>* =nullptr
  >
  array_view( std::initializer_list<U> il ):array_view(il.begin(), il.end()) {}
};

array_view 接受任何支援 .data() 的容器返回指向 T.size() 方法或陣列的指標,並將其刪除為連續 Ts 上的隨機訪問範圍。

它可能需要一個 std::vector<T>,一個 std::string<T> 一個 T[37],一個初始化列表(包括基於 {} 的那個),或者你支援它的其他東西(通過 T* x.data()size_t x.size())。

在這種情況下,我們可以從我們正在擦除的東西中提取的資料,以及我們的檢視非擁有狀態,意味著我們不必分配記憶體或編寫自定義型別相關的函式。

例項

改進將是在啟用 ADL 的上下文中使用非成員 data 和非成員 size