What is a view_closure in range-v3?

Viewed 265

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.

2 Answers

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_range argument and returns a view. For a range adaptor closure object C and an expression R such that decltype((R)) models viewable_­range, the following expressions are equivalent and yield a view:

C(R)
R | C

Given an additional range adaptor closure object D, the expression C | D is 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.

Related