
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: https://svn.boost.org/trac/boost/ticket/7630
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.)