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?