C++20 introduces the Ranges library, which dramatically changes how we process sequences. Instead of writing loops, temporary containers, and manual copies, ranges let us express intent directly on the data. Views are lazy transformations that avoid allocating intermediate storage, while ranges bring algorithms that operate over arbitrary ranges.
1. Why Ranges?
Before C++20, most algorithms required iterators or full containers:
std::vector <int> v = {1,2,3,4,5};
std::vector <int> result;
std::copy_if(v.begin(), v.end(), std::back_inserter(result),
[](int x){ return x % 2 == 0; });
This code copies matching elements into a new vector. With ranges, you can express the same idea as a pipeline:
auto evens = v | std::views::filter([](int x){ return x % 2 == 0; });
for (int n : evens) std::cout << n << ' ';
No temporary vector is created; the filter view lazily evaluates each element on demand.
2. The Core Components
| Component | Purpose |
|---|---|
std::ranges::views |
Namespace containing lazy, composable transformations |
std::ranges::action |
In-place transformations (e.g., std::ranges::sort) |
std::ranges::begin/end |
Generic accessors that work with any range |
std::ranges::size |
Size query that works on containers and views |
3. Building a Pipeline
Below is a complete example that:
- Reads a file line by line.
- Filters lines containing the word “error”.
- Transforms those lines to uppercase.
- Counts how many error lines were found.
#include <iostream>
#include <fstream>
#include <string>
#include <ranges>
#include <algorithm>
#include <cctype>
int main() {
std::ifstream file("log.txt");
if (!file) return 1;
auto lines = std::views::istream(file);
auto error_lines = lines
| std::views::filter([](const std::string& s){
return s.find("error") != std::string::npos;
})
| std::views::transform([](std::string s){
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c){ return std::toupper(c); });
return s;
});
for (auto& line : error_lines) {
std::cout << line << '\n';
}
std::cout << "Total errors: " << std::ranges::distance(error_lines) << '\n';
}
Key takeaways:
- istream View:
std::views::istreamlazily reads lines as needed. - Filter View: Eliminates non-error lines without storing them.
- Transform View: Performs the uppercase conversion on the fly.
- Distance: Works on the view to count elements without iterating twice.
4. Common View Types
| View | Description |
|---|---|
std::views::filter |
Selects elements that satisfy a predicate |
std::views::transform |
Applies a unary function to each element |
std::views::take / take_while |
Limits the number of elements |
std::views::drop / drop_while |
Skips elements |
std::views::reverse |
Provides a reversed view |
std::views::zip (from third‑party) |
Pairs elements from multiple ranges |
5. Performance Notes
- Lazy evaluation: Views compute elements only when iterated.
- No temporary containers: Reduces memory overhead and improves cache locality.
- Small function objects: Prefer
constexprlambdas to enable compile‑time optimization.
6. Advanced Usage
a. Custom View
You can write a view that generates Fibonacci numbers:
struct fibonacci_view : std::ranges::view_interface <fibonacci_view> {
struct iterator {
std::size_t cur = 0, next = 1;
std::size_t operator*() const { return cur; }
iterator& operator++() {
std::size_t tmp = cur + next;
cur = next; next = tmp;
return *this;
}
bool operator!=(const iterator&) const { return true; } // infinite
};
iterator begin() const { return {}; }
std::ranges::sentinel_t <iterator> end() const { return {}; }
};
b. Action vs View
If you need to modify a container in place:
std::vector <int> vec = {3,1,4,1,5};
vec | std::ranges::sort;
vec | std::ranges::reverse;
The std::ranges::action pipeline mutates vec directly.
7. Bottom Line
Ranges and views transform C++ code from a “loop‑heavy” language to a “pipeline‑oriented” one. By composing small, lazy transformations, you write more declarative, readable, and efficient code. The C++20 standard encourages this style; modern IDEs and compilers optimize these pipelines aggressively, making them a powerful tool for every C++ developer.