In a case like this:
auto pow = [](int i) {return i * i; };
auto closure = ranges::views::transform(pow);
closure seems to be a view_closure. I do get that last line does not make much sense, since transform is not applied anywhere. Actually, I could may as well pipe a vector x into closure and it would both compile and work properly.
But, what is a view closure? Is it a "function like" object that expects to be applied somewhere? What are its semantics?
I found this from Eric Niebler's range-v3 source code but there aren't any docs specifying it elsewhere.
I don't even get whether view_closure is intended for internal usage or for the users' end.
The view_closure class template in range-v3 that is an implementation strategy for what in C++20 became the range adaptor closure object concept:
A range adaptor closure object is a unary function object that accepts a
viewable_rangeargument and returns aview. For a range adaptor closure objectCand an expressionRsuch thatdecltype((R))modelsviewable_range, the following expressions are equivalent and yield a view:C(R) R | CGiven an additional range adaptor closure object
D, the expressionC | Dis well-formed and produces another range adaptor closure object such that the following two expressions are equivalent:R | C | D R | (C | D)
The result of transform(f) is a range adaptor closure object, which you can apply to a viewable_range either via pipe as r | transform(f) or via call as transform(f)(r), either of which will give you some kind of transform_view adaptor.
More broadly, transform itself is a range adaptor object which is defined in a way such that transform(f) gives you a range adaptor closure object such that transform(r, f), r | transform(f), and transform(f)(r) are all equivalent.
view_closure, the class template, is necessary to ensure that stuff like this works:
auto adaptor = transform(f) | filter(g) | chunks(n);
That is, you can build up a pipeline without having a range, and the result of that is a range adaptor closure object that you can then apply to a range - r | adaptor would be equivalent to r | transform(f) | filter(g) | chunks(n) which is equivalent to chunks(filter(transform(r, f), g), n).
That class template basically affects what operator| does, among other things. You only need to use it if you're creating your own range adaptor, it's not something you need to care about as a user of ranges otherwise.
view_closure is not a type, it is a template. The exact type of that expression is an instantiation of that template with an unnamed closure type (i.e. decltype(pow)). It is an implementation detail.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With