0

I'm new to range-v3. I started by write a program that generates a range of integers, modifies it, and prints out the resulting range. I used a modifier from the actions library, which rendered my code non-iterable. Could someone help me understand how to convert a ranges::action::action_closure into an iterable?

Here's the example I started with - a function that generates and prints out a range of numbers. This code works fine and compiles.

void generate_and_print_numbers_using_streams_and_iterators() {
  auto v = views::iota(1, 5);  // <-- this code works fine with streams and iterators.

  // this works
  cout << v << endl;

  //this works too
  for (auto s: v) {
    cout << s << ", ";
  }
  cout << endl;

  // and this works too
  for (auto it = v.begin(); it != v.end(); ++it) {
    cout << *it << ", ";
  }
  cout << endl;
}

Then I tried introducing the action I mentioned. This code no longer compiles - v is no longer a view, but an action_closure which does not define begin() and end() functions.

void generate_and_print_numbers_using_streams_and_iterators() {
  // I REPLACED THIS:
  // auto v = views::iota(1, 5);
  // WITH THIS:
  auto v = action::push_back(views::iota(1, 5)) | actions::unique;  // Wrapped iota in push_back

  // .. the remainder of the function is unchanged

I tried searching through the documentation of ranges-v3, as well as googling this conversion. The only thing I found was the following article that shows how to convert a view to a concrete container (a vector).

I will appreciate any help on this topic.

Piotr Trochim
  • 693
  • 5
  • 15
  • What're you hoping to accomplish here? What's the intent of `push_back(iota(1, 5))`? That's an odd expression to see. – Barry Mar 21 '22 at 21:45
  • I wanted to generate a range of numbers, modify that range, and print the numbers. I found the instruction to wrap iota in push_back in this post - https://stackoverflow.com/questions/30425417/how-to-write-a-range-v3-action-for-random-shuffle – Piotr Trochim Mar 22 '22 at 22:14

1 Answers1

1

Actions do not return a light-weight ephemeral object that can be lazily iterated over like view operations do. Actions are applied eagerly to actual containers and return actual containers, but still can be composed together.

In the following std::vector<int>() is an r-value that gets filled via push_back which returns an r-value that is then passed to the reverse action. All of this processing happens eagerly, akin to normal nested function calls but using the pipeline syntax:

void do_something_with_a_push_back_action() {
    std::vector<int> vec = std::vector<int>() | 
        ranges::actions::push_back(ranges::views::iota(1, 5)) | 
        ranges::actions::reverse;

    for (int val : vec) {
        std::cout << val << "\n";
    }
}
jwezorek
  • 8,592
  • 1
  • 29
  • 46
  • It makes sense that actions modify the containers - that one should pipe a container through a set of actions. Thank you! – Piotr Trochim Mar 22 '22 at 22:17