๐ŸŽ“ A1Learner
๐Ÿ”
0 of 28 lessons completed

C++ Ranges in Practice

Ranges practice combines a pipeline with a loop that collects the results. The collected values land in a container the program owns.

Collecting squares from a counted sequence

std::views::iota counts from 1 up to 7 without including 7. The loop pushes each squared value into the vector.

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

int main() {
  auto squares = std::views::iota(1, 7) | std::views::transform([](int n) {
    return n * n;
  });
  std::vector<int> kept;
  for (int n : squares) {
    kept.push_back(n);
  }
  std::cout << "Squares:";
  for (int n : kept) {
    std::cout << " " << n;
  }
  std::cout << std::endl;
  return 0;
}

Filtering and changing words

The filter keeps words with at least four letters. The transform builds an uppercase copy of each word that passes.

#include <cctype>
#include <iostream>
#include <ranges>
#include <string>
#include <vector>

int main() {
  std::vector<std::string> words = {"cat", "house", "sun", "garden", "tree"};
  auto shout = [](std::string word) {
    std::string loud;
    for (char c : word) {
      loud += static_cast<char>(std::toupper(c));
    }
    return loud;
  };
  auto view = words | std::views::filter([](std::string word) {
    return word.size() >= 4;
  }) | std::views::transform(shout);
  std::vector<std::string> kept;
  for (std::string word : view) {
    kept.push_back(word);
  }
  std::cout << "Long words:";
  for (std::string word : kept) {
    std::cout << " " << word;
  }
  std::cout << std::endl;
  return 0;
}

Reversing and finding the largest

std::ranges::reverse turns the vector around in place. std::ranges::max_element returns a position, and reading through it with * gives the largest value.

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

int main() {
  std::vector<int> scores = {42, 17, 88, 59};
  std::cout << "Before:";
  for (int n : scores) {
    std::cout << " " << n;
  }
  std::cout << std::endl;
  std::ranges::reverse(scores);
  std::cout << "After:";
  for (int n : scores) {
    std::cout << " " << n;
  }
  std::cout << std::endl;
  auto best = std::ranges::max_element(scores);
  std::cout << "Largest: " << *best << std::endl;
  return 0;
}

Example

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

int main() {
  auto board = std::views::iota(1, 9) | std::views::filter([](int n) {
    return n % 2 == 0;
  }) | std::views::transform([](int n) {
    return n * 10;
  });
  std::vector<int> rounds;
  for (int n : board) {
    rounds.push_back(n);
  }
  std::cout << "Board:";
  for (int n : rounds) {
    std::cout << " " << n;
  }
  std::cout << std::endl;
  int total = 0;
  for (int n : rounds) {
    total += n;
  }
  std::cout << "Total: " << total << std::endl;
  return 0;
}

Key points

  • Use std::views::iota to make a counted sequence without building a container first.
  • Use a loop with push_back to collect the values a view produces.
  • A view does not fill a vector through the vector constructor, because some views end with a marker that is not a position.
  • Use std::ranges::reverse to turn a container around in place.
  • std::ranges::max_element returns a position for the largest value.

In this example, iota counts the rounds from 1 to 8. The filter keeps the even rounds. The transform multiplies each round by ten, and the collecting loop stores the results. A second loop adds the stored values into the printed total.

Note

A collected vector owns its values, so it stays usable after the view is gone.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

Why do the programs in this lesson collect a view with a loop instead of the vector constructor?