c++ - Why no "variant" any in boost or Standard? -


one advantage of any on variant is, 1 not need specify types, may contain. i've noticed, number of types variant may contain grows, people tend switch any @ point, because don't keep track of types anymore. think hybrid between any , variant possible. 1 store "placeholder" (via placement new) of any in aligned_storage, size calculated in constexpr function or template metafunction, sample of largest types, may end being stored. user, on other hand, not need specify types, any might contain. any throw @ time, if user try store larger aligned_storage in there.

does such "variant_any" class exist? there inherent problem idea?

here basic some.

the t copy/assign/move/etc can implemented in terms of emplace. sfinae using can_store<t> can ensure types some can store assignable it, avoiding needless exceptions.

currently, moving some destroys contents instead of moving it. , some can empty (they "nulllable").

load_from 'can-fail' copy constructor some -- returns false on failure. add 'cannot-fail' smaller some (even copy/assignment operator) complete it.

some_meta manual virtual function table. 1 exists per type t store in some of size. stores type-erased operations on type t some wants use (in case, copy move , destroy), plus data type (size, alignment , type identity). augmented additional operations comparison , serialization. binary operations, logic handle "no matching type" has considered. stuff serialization, i'd have call free function serialize , deserialize on t. in both cases, impose additional requirements on some can store (you can, bit of work, handle "maybe serialize", gets messy).

you imagine system can store set of operations perform on data (binary , unary) , pass said operations bundled in types passed some. @ point, approaching boost's type erasure library, however.

namespace details { template<std::size_t size, std::size_t align=0> struct storage_helper {   using type = std::aligned_storage_t<size, align>;   enum { alignment = alignof(type), size = size }; }; template<std::size_t size> struct storage_helper<size, 0> {   using type = std::aligned_storage_t<size>;   enum { alignment = alignof(type), size = size }; }; template<std::size_t size, std::size_t align> using storage_helper_t = typename storage_helper<size,align>::type;  template<class t>using type=t; struct some_meta {   type<void(void*)>* destroy;   type<void(void* dest, void const* src)>* copy;   type<void(void* dest, void* src)>* move;   std::type_index type;   size_t size;   size_t align;   template<class t> static some_meta const* get() {     static const some_meta retval( create<t>() );     return &retval;   };   private:   template<class t> static some_meta create() {     return {         [](void* p){ ((t*)p)->~t(); },         [](void* out, void const* in){ new(out)t(*(t*)in); },         [](void* dest, void* src) { new(dest)t(std::move(*(t*)src)); },         typeid(t),         sizeof(t),         alignof(t)     };   } }; }  template<class>struct emplace_as{};  template< std::size_t size, std::size_t align=0 > struct {   enum { align = details::storage_helper<size, align>::alignment };   using data_type = details::storage_helper_t<size, align>;    template<size_t, size_t> friend struct some;   template<class t> struct can_store :     std::integral_constant< bool, ((align%alignof(t))==0) && sizeof(t) <= size) >   {};    template<size_t x, size_t a>   static bool can_fit( some<x,a> const& o ) {     if (x<=size && ((align%some<x,a>::align)==0)) return true; // should cause optimizations     if (!o.meta) return true;     if (o.meta->size > size) return false;     if (o.meta->align > align) return false;     return true;   } private:   data_type data;   details::some_meta const* meta = nullptr; public:   // true iif (exactly) t   template<class t>   bool is() const {       return meta && (meta->type == typeid(t));   }    explicit operator bool()const { return meta!=nullptr; }    template<class t>   t* unsafe_get() { return reinterpret_cast<t*>(&data); }    template<class t>   t* get() { if (is<t>()) return unsafe_get<t>(); else return nullptr; }    void clear() { if (meta) meta->destroy(&data); meta = nullptr; }    template<class t, class... args>   std::enable_if_t< can_store<t>{} >   emplace(args&&...args) {     clear();      new(&data) t(std::forward<args>(args)...);     meta = details::some_meta::get<t>();   }   some()=default;   some(some const& o) {     *this = o;   }   some(some const&&o):some(o){}   some(some&o):some(const_cast<some const&>(o)){}   some(some&& o) {     *this = std::move(o);   }    some& operator=(some const&o) {     if (this == &o) return *this;     clear();     if (o.meta) {       o.meta->copy( &data, &o.data );       meta=o.meta;     }     return *this;   }           some& operator=(some &&o) {     if (this == &o) return *this;     clear();     if (o.meta) {       o.meta->move( &data, &o.data );       meta=o.meta;       o.clear();     }     return *this;   }   some& operator=(some const&&o) { return *this=o; }   some& operator=(some &o) { return *this=const_cast<some const&>(o); }    // non-some:   template<class t,class=std::enable_if_t<can_store<std::decay_t<t>>{}>>   some(t&& t){     emplace<std::decay_t<t>>(std::forward<t>(t));   }   template<class t, class...args,class=std::enable_if_t<can_store<t>{}>>   some( emplace_as<t>, args&&...args ){     emplace<t>(std::forward<args>(args)...);   }   template<class t,class=std::enable_if_t<can_store<std::decay_t<t>>{}>>   some& operator=(t&&t){     emplace<std::decay_t<t>>(std::forward<t>(t));     return *this;   }    template<size_t x, size_t a>   bool load_from( some<x,a> const& o ) {     if ((void*)&o==this) return true;     if (!can_fit(o)) return false;     clear();     if (o.meta) {       o.meta->copy( &data, &o.data );       meta=o.meta;     }     return true;   }   template<size_t x, size_t a>   bool load_from( some<x,a> && o ) {     if ((void*)&o==this) return true;     if (!can_fit(o)) return false;     clear();     if (o.meta) {       o.meta->move( &data, &o.data );       meta=o.meta;       o.clear();     }     return true;   }   ~some() { clear(); } };  template<class t, class...ts> using some_that_fits = some< (std::max)({sizeof(t),sizeof(ts)...}), (std::max)({alignof(t),alignof(ts)...}) >; 

the meta object manually implemented virtual function table, basically. reduces memory overhead of given some 1 pointer (above storage buffer).

live example

as demonstrated above, quite viable.

note create returns pointer same meta same type t, if called more once.

i have exercised half code paths in test above. others have bugs.

some_that_fits lets pass set of types, , returns some type fits types.

no exceptions, other generated operations on stored types said stored types, thrown. when possible, test @ compile time ensure types fit.

i possibly add support greater alignment, small storage types starting them @ offset data?


Comments

Popular posts from this blog

javascript - Any ideas when Firefox is likely to implement lengthAdjust and textLength? -

matlab - "Contour not rendered for non-finite ZData" -

delphi - Indy UDP Read Contents of Adata -