ericniebler / range-v3

Range library for C++14/17/20, basis for C++20's std::ranges
Other
4.05k stars 437 forks source link

Enable borrowed range for ranges without copy constructor by default #1780

Closed correaa closed 1 year ago

correaa commented 1 year ago

This originated from a discussion at cppnow with @brevzin. This is a placeholder, I will add more details later.

I suggested that the range library could guess enable_borrowed_range from syntactic peculiarities of the range.

Not sure I am correct, but one way could be to deduce enable_borrowed_range when the range is not copy constructor. There could be other ways.

I mention this because this is the particular property that I find in that the subviews (subarrays) in my library. In it, I reached the conclusion that subarrays with well defined reference semantics cannot afford a copy constructor.

This is the section that explains subarrays: https://gitlab.com/correaa/boost-multi#slices-and-strides , you can find more details in other parts of the document. My library is largely compatible with Ranges, https://gitlab.com/correaa/boost-multi#range-v3

Another, perhaps simpler, way to get to this conclusion is that a range that is conceptually borrowed and doesn't have a copy constructor cannot use the trick of making a copy before the algorithm and therefore the library can see that is either, i) completely bad designed or ii) must be a borrowed range. The library should lean for the second.

brevzin commented 1 year ago

Not sure I am correct, but one way could be to deduce enable_borrowed_range when the range is not copy constructor. There could be other ways.

As I mentioned, the canonical borrowed ranges are things like... subrange<int*>, string_view, span<T>, rev_view<V>. All of these are copyable.

On the flip side, ranges that aren't copyable are not necessarily borrowed either - views::istream<T> isn't a borrowed range, nor is std::generator<T>, nor is join_view<V> when V is a range of prvalue ranges. In general, noncopyable views are noncopyable precisely because they need to store state in the view itself - so they cannot be borrowed.

But a borrowed range need not be copyable either, subrange<I> for a move-only iterator is still borrowed, despite not being copyable.