Steven Schveighoffer wrote:
On Sat, 02 Jan 2010 13:06:25 -0500, Andrei Alexandrescu <[email protected]> wrote:

Steven Schveighoffer wrote:
On Fri, 01 Jan 2010 18:45:35 -0500, Andrei Alexandrescu <[email protected]> wrote:

Rainer Deyke wrote:
Andrei Alexandrescu wrote:
If the implementor of consume() forgets to call save(), the situation is unpleasant albeit not catastrophic: for most struct ranges things will continue to work, but for class ranges the function will fail to perform
to spec. I don't know how to improve on that.
Require that all ranges are structs. If you want to implement a range
as a class, use a wrapper struct that creates a new object in its
postblit function. The wrapper struct can be made generic and placed in
the standard library.
 Same performance as the current approach, slightly more effort on the
part of the range implementor, much easier and less error-prone on the
side of the range user.

Oh, besides it doesn't work for struct ranges that iterate one-pass streams.
 What does save do in those cases?
 -Steve

It provides a syntactic differentiation between input ranges and forward ranges.

STL's input iterators are syntactically indistinguishable from forward iterators. Because of that, all STL algorithms that expect forward ranges will also compile and run with input ranges, although never with the expected result. This has been a lingering problem with C++98, and a key motivator for concepts. Since syntactic differences cannot be used to distinguish between input and forward iterators, the reasoning went, we need something else as a discriminator - and that would be a concept: someone who defines an input iterator declares it obeys the input iterator concept, whereas someone defining a forward iterator declares it obeys the forward iterator concept.

During the meltdown of concepts, a number of people including Bjarne Stroustrup and myself have suggested that a simple workable solution would be to define an extra function a la "save" that is used in algorithms and only supported by forward iterators, but not by input iterators. Then, algorithms use save() and will correctly refuse to compile calls with input iterators. The remaining risk is that someone writes an algorithm and forgets to use save().

Would it not be as useful then to just define attributes on the type and save a bunch of useless/weird looking code?

that is, have an enum value inside the type that defines its state can be saved. It seems to me like save is the equivalent of that anyways, since its possible to forget to use it, and still have your code compile.

If you have an enum that says a range's state can be saved, then you still need a function to effect that save :o). So you added, not removed, bloat.

Basically, it appears to me that save either a) doesn't compile or b) is the equivalent of assignment. It doesn't seem to add much to the functionality.

No, for class ranges save() is nontrivial (a sort of clone). I suspect even struct ranges for certain file-oriented stuff would do nontrivial work (e.g. open the file anew and fseek() on the current position etc.)

This is all except for classes, which I think have no business being ranges in the first place.

Well then how would the container hierarchy work? It does need range interfaces. How does dcollections deal with that?


Andrei

Reply via email to