刪除到 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()
方法或陣列的指標,並將其刪除為連續 T
s 上的隨機訪問範圍。
它可能需要一個 std::vector<T>
,一個 std::string<T>
一個 T[37]
,一個初始化列表(包括基於 {}
的那個),或者你支援它的其他東西(通過 T* x.data()
和 size_t x.size()
)。
在這種情況下,我們可以從我們正在擦除的東西中提取的資料,以及我們的檢視非擁有狀態,意味著我們不必分配記憶體或編寫自定義型別相關的函式。
例項 。
改進將是在啟用 ADL 的上下文中使用非成員 data
和非成員 size
。