The viewable_range concept specifies the requirements of a range type that can be converted to a view safely.
It's mandatory implementation roughly states that a range
further satisfies viewable_range
if either
- it's simply a view, e.g.
std::string_view
, or - it's an lvalue reference (even when its reference-removed type is not a view), e.g.
std::vector<int>&
, or - it's a movable object type (i.e. not reference type), e.g.
std::vector<int>
My questions are:
- What idea does this concept capture? Specifically, how could its instance "be converted to a view safely" and why do I want such conversion? What does "safety" even mean here?
- Do you always use
viewable_range
to constrain universal reference? (i.e. the only chanceT
to be deduced to lvalue reference type.) This is the case for standard range adaptor (closure) objects. - Range adaptor (closure) objects are modified to take a
range
as first parameter in C 23. Is there other usage forviewable_range
concept since then? - For application development, when to use
viewable_range
instead ofview
orrange
?
CodePudding user response:
What idea does this concept capture? Specifically, how could its instance "be converted to a view safely" and why do I want such conversion? What does "safety" even mean here?
Any range can be converted to a view, simply by doing this:
template <input_range R>
auto into_view(R&& r) {
return ref_view(r);
}
But this isn't really a great idea. If we had an rvalue range (whether it's a view or not), now we're taking a reference to it, so this could dangle if we hold onto the resulting view too long.
In general, we don't want to hold onto references to view
s - the point of a view
is that range adaptors hold them by value, not by reference. But also in general, we don't want to hold non-view ranges by value, since those are expensive to copy.
What viewable_range
does is restrict the set of ranges to those where we can covert to a view without added concern for dangling:
view
s should always be by value - so an lvalueview
is only aviewable_range
if it is copyable. An rvalueview
is always aviewable_range
(becauseview
s have to be movable).- an lvalue non-
view
range is always aviewable_range
because we take aref_view
in that case. This of course has potential for dangling, but we're taking an lvalue, so it's the safer case. - an rvalue non-
view
range was originally rejected (because our only option wasref_view
and we don't want to refer in this case), but will start to be captured asowning_view
(as of P2415).
So basically, the only thing that isn't a viewable range is an lvalue non-copyable view, because of the desire to avoid taking references to views.
Do you always use
viewable_range
to constrainuniversalforwarding reference? (i.e. the only chance T to be deduced to lvalue reference type.) This is the case for standard range adaptor (closure) objects.
No. Only if what you want to do with the forwarding reference is convert it to a view and store the resulting view. Range adaptors do this, but algorithms don't need to - so they shouldn't use that constraint (none of the standard library algorithms do).
Range adaptor (closure) objects are modified to take a range as first parameter in C 23. Is there other usage for viewable_range concept since then?
The term range adaptor closure object is relaxed because now that we can have user-defined range adaptor closure objects (P2387), we can't really enforce what it is that they actually do.
But the standard library range adaptor closure objects still do require viewable_range
(by way of all_t
).
For application development, when to use
viewable_range
instead ofview
orrange
?
This is really the same question as (2). If what you want is to take any range and convert it to a view to be stored, you use viewable_range
- so when you're writing a range adaptor.