Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Range transformations with stateful lambdas and std::views::drop

it’s my first time digging into the new <ranges> library and I tried a little experiment combining std::views::transform with a stateful lambda and ‘piping’ the resulting range to std::views::drop:

#include <iostream>
#include <ranges>
#include <vector>

using namespace std;

int main() {
    auto aggregator = [sum = 0](int val) mutable
                      {
                          return sum += val;
                      };

    vector<int> data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    cout << "Expected:\n";
    int sum = 0;
    for (int val : data) {
        cout << (sum += val) << ' ';
    }
    cout << '\n';

    cout << "Transformation:\n- - - ";
    for (int val : data | views::transform(aggregator) | views::drop(3)) {
        cout << val << ' ';
    }
    cout << '\n';
}

The output was:

Expected:
1 3 6 10 15 21 28 36 45 55 
Transformation:
- - - 4 9 15 22 30 39 49

Now, the difference between each expected and actual output is 1 + 2 + 3 = 6. I am guessing it is a result of the lazy evaluation of ranges that causes std::views::drop to disregard the first three transformations.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Is there a way for me to force the evaluation of the aggregator functor for the three elements I drop? Or are stateful lambdas and ranges considered incompatible?

>Solution :

transform_view is required to be a pure function. This is codified in the regular_invocable concept:

The invoke function call expression shall be equality-preserving and shall not modify the function object or the arguments.

This is important to allow transform_view to not lie about its iterator status. Forward iterators, for example, are supposed to allow multipass iteration. This means that the value at each iterator position within the range must be independent of any other iterator position. That’s not possible if the transformation functor is not pure.

Note that all predicate functors are also regular_invocable. So this also applies to things like filter_view and take_while_view.

Note that the algorithm transform does not have this requirement.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading