On 15-11-2016 23:53, Joaquin M López Muñoz wrote:
El 15/11/2016 a las 18:38, Thorsten Ottosen escribió:
Hi Joaquin,
[...]
A. This is very useful.
Thanks! Glad you find it interesting.
B. I'm still wondering if requirering copyability is a good thing. After all, references and pointers may be used elsewere in the program where copying is really not a good idea. Could it make sense to have a variation of cloneable:
void clone( void* storage ) const;
// essentially a call to protected or private copy-constructor: // new(storage) T( *this )
which is then used internally when copying is needed? And when no copying is needed, the container is not copyable. To insert elements that are not copyable we would just use emplace with a type argument:
coll.emplace<derived>( x, y );
Strictly speaking, copyability is not required, but as concrete types are stored in rellocatable vectors they must be verify the following:
* be MoveConstructible, * be Moveassignable or have a noexcept move constructor.
Otherwise, segments wouldn't be able to grow beyond its initial capacity.
Right. But maybe that access to be hidden to the outside world like in Boost.Serialiation: friend class boost::poly_collection::access; Then perhaps your library could work with private and protected copy/move operations? My point is that we are still doing OO-programming, and copying/moving is not natural operations for objects in that domain.
As for your clone() proposal, I fail to see why this is preferrable to simply requiring (move/copy) constructibility. Please note that moving/copying in Boost.PolyCollection happens in a non-virtual environment, so we don't need the virtual-enabled clone mechanism as envisioned in the Clonable concept of Boost.PtrContainer. Please correct me if I'm missing your point.
You could always devirtualize it. Anyway, the point is, to hide the copy/move semantics to clients of my class hierarchy. Take the following use-case: I know what types to register and how many of each I'm going to insert. For that case I should be able to construct, reserve and insert without having a copyable or movable type. Anyway, I would be ok with just being able to make copy/move operations protected.
C. perhap some range versions of local iterators would be nice?
Care to elaborate? I've basically replicated the usual interface of standard containers, of course open to consider justified improvements on that.
For example, for(auto first=c.begin<warrior>(),last=c.end<warrior>(); first!=last;++first) could be nice to write for( auto x : c.range<warrior>() ) or for( auto x : restituted_range<warrior>(c) )
D. I don't get the use of numeric_limits<T>::max() for capacity of an empty container. I would be perfectly happy with 0 unless there is something we cannot do with that definition.
Not a strong opinon on that. Having capacity()==infinite for a segment-less collection makes sense from a mathematical point of view, but other than that 0 could work equally well. If this eventually make it into an official proposal I'd adopt whatever the community thinks makes the most sense.
ok, it confused me, so chances are that it will confuse the average programmer and take up brain cycles for no reason.
E. Boost.PtrContainer does not throw exception when a container cannot be cloned or compared. Maybe its must be possible to get compile errors here too?
I've re-read Boost.PtrContainer docs and seems like the containers require Base to be clonable, which is tantamount to requiring copyability for all derived classes in Boost.PolyCollection. Am I wrong here? What's the behavior if a Base is not clonable?
It's a compile error. But I think I don't give the compile error until the cloning is needed.
that is, would that not guarantee devirtualization?
Very good observation. Yes, that would force devirtualization. The thing can be packed into something more generic:
sweet. kind regards -Thorsten