<snip> big thread about polymorphic container ... </snip>
I hope I didn't miss anything in the thread. If I'm repeating something, sorry.
I don't think we want or need to limit what we put into the container. Neither by forcing certain virtual functions onto the base class, nor by limiting what the contained types can and can't do (like have pointers to themselves and do funky things in their copy/move constructors).
When push_back<Triangle> is called, we create an instance of an ItemHandler<Triangle> class, that derives from BaseItemHandler, and implements copy/move virtually. ie type-erasure. ItemHandler<Triangle> knows how to move/copy Triangles. It is not Triangle's job!
We put the ItemHandler<Triangle> in a map
. Note: - we only need *one* ItemHandler<Triangle> for all Triangles, not one for each. - Triangle doesn't have any do_copy/move/size virtual functions, ItemHandler<Triangle> does.
- we can store Triangle mixed in with Squares and other shapes or isolated in a group of Triangles. Maybe different containers will choose differently. - if stored mixed together, then we have a parallel vector that is a pointer to BaseItemHandler* for each item in the main vector.
ie (typed in email, so should not compile)
struct BaseItemHandler { virtual void do_copy(char * dest, char const * src) const = 0; virtual std::size_t size() const = 0; };
template <typename T> struct ItemHandler : BaseItemHandler { virtual void do_copy(char * dest, char const * src) const { T * typed_src = reinterpret_cast
(src); new (dest) T(*typed_src); // in-place copy construct } virtual std::size_t size() const { return sizeof(T); } }; template <typename Item> void classifier::push_back(Item const & item) { char const * key = typeid(Item).name(); // or use raw name or address of type info
// add/get handler to/from map HandlerMap::iterator itHandler = handlerMap.find(key); BaseItemHandler * handler = 0; if (itHandler == handlerMap.end()) { // new type we haven't seen before handler = new ItemHandler<Item>; handlerMap[key] = handler; } else { handler = *itHandler; }
char * space = make_space_for_item(handler->size()); // make space in vector<char> handler->do_copy(space, item); inplace copy construct How does make_space_for_item assure the return value is aligned
On 08/27/13 23:51, Gottlob Frege wrote: properly for an Item type? [snip]