template<class T, std::size_t sz, std::size_t algn>
struct poly {
,如果你不害怕但你應該
poly_vtable<T> const* vtable=0;
std::aligned_storage_t<sz, algn> data;
我們以後可以覆蓋虛函數表。
T* get() { return vtable->get(&data); }
T const* get() const { return vtable->get((void*)&data); }
示例使用vtable。下面是設置:
template<class U, class...Args>
U* emplace(Args&&...args){
static_assert(sizeof(U)<=sz && alignof(U)<=algn, "type too large");
clear();
U* r = ::new((void*)&data) U(std::forward<Args>(args)...);
vtable = get_poly_vtable<T,U>();
return r;
}
副本:
poly(poly const& o){
if (!o.vtable) return;
o.vtable->copy(&data, &o.data);
vtable=o.vtable;
}
poly(poly&& o){
if (!o.vtable) return;
o.vtable->move(&data, &o.data);
vtable=o.vtable;
}
poly& operator=(poly const& rhs) {
if (this == &rhs) return *this;
clear();
if (!rhs.vtable) return *this;
rhs.vtable->copy(&data, &rhs.data);
vtable = rhs.vtable;
return *this;
}
poly& operator=(poly&& rhs) {
if (this == &rhs) return *this;
clear();
if (!rhs.vtable) return *this;
rhs.vtable->move(&data, &rhs.data);
vtable = rhs.vtable;
return *this;
}
破壞:
void clear(){
if (!vtable) return;
vtable->dtor(&data);
vtable=nullptr;
}
~poly(){clear();}
指針等的操作:從T中派生的類型
explicit operator bool()const{return vtable;}
T& operator*(){ return *get();}
T const& operator*() const{ return *get();}
T* operator->(){ return get();}
T const* operator->() const{ return get();}
構建體:
template<class U,
class dU=std::decay_t<U>,
class=std::enable_if_t<!std::is_same<dU, poly>{}>,
class=std::enable_if_t<std::is_base_of<T, dU>{}>
>
poly(U&& u) {
emplace<std::decay_t<U>>(std::forward<U>(u));
}
};
請注意,此類型時const指const值。
這個想法是,poly<T>
是T
類型的多態值。它有大小限制。
您可以使用T*
vtable來安排其他操作的多態性。
template<class T>
struct poly_vtable{
T*(*get)(void*)=0;
void(*copy)(void*,void const*)=0;
void(*move)(void*,void*)=0;
void(*dtor)(void*)=0;
};
template<class T, class U>
poly_vtable<T> make_poly_vtable() {
return {
[](void* ptr)->T*{ return static_cast<U*>(ptr); },
[](void* dest, void const* src){ ::new(dest) U(*static_cast<U const*>(src)); },
[](void* dest, void* src){ ::new(dest) U(std::move(*static_cast<U*>(src))); },
[](void* ptr){ static_cast<U*>(ptr)->~U(); }
};
}
template<class T, class U>
poly_vtable<T> const* get_poly_vtable() {
static const auto r = make_poly_vtable<T,U>();
return &r;
}
get_poly_vtable<T,U>()
返回指向靜態局部poly_vtable<T>
與實現的每個操作。
Live example。
現在你可以有一個基於vtable的多態值類型。
相同的技術可以擴展到更多的操作;簡單地轉換爲基礎,並使用真正的vtables更容易。
使用這個,你存儲一個poly<IMyIterator, 64, alignof(IMyIterator)>
。這是一個包含64字節緩衝區的值類型。
的另一種方法,以減少間接將與可能的重複範圍探視替換每個項目的探視的概念。
如果每回調一次訪問10個項目的範圍,則調用虛擬方法的開銷比每個回調的開銷少10倍。
您可以使用範圍對象創建輸入迭代器,範圍對象最多可包含10個緩衝區項,並在到達結尾時自動重建它,如果有更多可用的批量獲取數據。
是的,這個就地手卷虛擬表的實現確實讓我害怕:) 我想我會繼續與我目前的實施工作,如果基準測試表明,單個迭代器解引用增加了太多的開銷,我按照你的建議緩衝結果。 或者也許我仍然通過封裝來讓太多的底層實現顯示,我應該找到更好的抽象來處理這個問題。 – AliaumeM