Boost logo

Boost :

Subject: Re: [boost] [range] fat iterators?
From: Luc Danton (lucdanton_at_[hidden])
Date: 2013-11-07 21:23:59

On 2013-11-07 21:49, Jonathan Wakely wrote:
> On 7 November 2013 17:27, Nathan Ridge wrote:
>> Jeffrey Yaskin posted a candidate design, implemented for filter_iterator,
>> here:
>> What do you think about this design?
> That's beautiful!
> My solution to the temporary range problem is simpler, but as
> mentioned in Jeffrey's patch to the docs, for ranges that store an
> iterator pair it wastes the space of a reference member in the lvalue
> case, and doesn't vanish to nothing in C++03 mode:
> template<typename R>
> class adaptor
> {
> R r; // R is a range or an lvalue-reference-to-range
> public:
> explicit
> adaptor(R&& r) : r(std::forward<R>(r)) { }
> // ...
> };
> template<typename R>
> adaptor<R>
> adapted(R&& r)
> { return adaptor<R>{std::forward<R>(r)}; }

I generally make use of this solution (i.e. in general and for things
other than ranges), but after trying it for ranges I balked and switched
to storing decayed copies. The reason is that a range abstraction
provides an 'indirection' at least in a moral sense, if not in
actuality. So you get aliasing issues:

     some_range r;
     auto a = adapted(r);
     auto b = adapted(r);

     // consume a:
     for(auto&& item: a);

     // now r has been touched!

     // likely to do the wrong thing
     for(auto&& item: b);

While there is the option of doing adapted(decay(r)) to express
'construct an adapted range from r that stores its own copy' (similarly
to uses of ref and reference_wrapper in C++03 code, although inverted),
my concern is that aliasing is not the most useful default for ranges.
(Strictly from a semantics point of view, I've never checked the impact
on the generated code.)

Boost list run by bdawes at, gregod at, cpdaniel at, john at