Ranges & Views (C++20)
Composable, lazy data transformations using the C++20 ranges library
The Problem with Traditional Loops
Traditional C++ requires verbose loops and temporary containers for data transformations.
// Traditional approach: verbose and error-prone
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Step 1: Filter evens
std::vector<int> evens;
for (int n : numbers) {
if (n % 2 == 0) {
evens.push_back(n);
}
}
// Step 2: Transform to squares
std::vector<int> squares;
for (int n : evens) {
squares.push_back(n * n);
}
// Step 3: Take first 3
std::vector<int> result;
for (size_t i = 0; i < std::min(squares.size(), size_t{3}); ++i) {
result.push_back(squares[i]);
}
// Issues: Multiple allocations, verbose, hard to read intentC++20: Ranges Pipeline
The ranges library provides composable, lazy operations using the pipe operator.
#include <ranges>
#include <vector>
namespace rv = std::views;
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto result = numbers
| rv::filter([](int n) { return n % 2 == 0; })
| rv::transform([](int n) { return n * n; })
| rv::take(3);
// No intermediate containers! Each element flows through the pipeline.
for (int n : result) {
std::cout << n << " "; // Output: 4 16 36
}Standard Views
| View | Description |
|---|---|
| filter | Keep elements matching predicate |
| transform | Apply function to each element |
| take | First N elements |
| drop | Skip first N elements |
| reverse | Reverse order |
Lazy Evaluation
Views do not compute until you iterate. This enables efficient composition.
std::vector<int> data(1'000'000);
auto pipeline = data
| rv::filter([](int n) { return n % 2 == 0; })
| rv::transform([](int n) { return n * n; })
| rv::take(10);
// Only processes elements until 10 even numbers are found
for (int n : pipeline) {
std::cout << n << " ";
}