struct many_vtable {
void(*dtor)(void*);
void(*print)(void const*,std::ostream&);
};
template<class T>struct tag_t{};
template<class T>constexpr tag_t<T> tag = {};
template<class T>
many_vtable const* make_many_vtable(tag_t<T>){
static const many_vtable retval = {
// dtor
[](void* p){
reinterpret_cast<T*>(p)->~T();
},
// print
[](void const*p, std::ostream& os){
os<<*reinterpret_cast<T const*>(p);
}
};
return &retval;
}
struct many {
many_vtable const* vtable=nullptr;
std::aligned_storage_t<100, alignof(double)> buff;
void clear(){if(vtable) vtable->dtor(&buff);vtable=nullptr;}
~many(){ clear(); }
many()=default;
many(many const&)=delete; // not yet supported
many& operator=(many const&)=delete; // not yet supported
explicit operator bool()const{return vtable!=nullptr;}
template<class T,class...Args>
void emplace(Args&&...args){
static_assert(alignof(T) <= alignof(double), "not enough alignment");
static_assert(sizeof(T) <= 100, "not enough size");
clear();
::new((void*)&buff) T(std::forward<Args>(args)...);
vtable=make_many_vtable(tag<T>);
}
friend std::ostream& operator<<(std::ostream& os, many const&m){
if(!m.vtable) return os;
m.vtable->print(&m.buff, os);
return os;
}
};
这是手动 vtable 设计。它可以存储最多 100 个字节的对齐小于可以打印到流的双精度的任何内容。
“擦除”到更多(或不同)操作很容易。例如,能够复制/移动到另一个许多。
它不违反标准,并且与链接示例具有相似的开销。
many m;
m.emplace<int>(3);
std::cout << m << '\n';
m.emplace<double>(3.14);
std::cout << m << '\n';
活生生的例子。
这是手动 vtable,因为我们基本上是手动重新实现 vtable 概念。