cpp20 · advanced

C++20 Ranges & views — Lazy Zero-Copy Pipelines

C++20 Ranges provides a composable, lazy pipeline for transforming sequences. A range is anything with begin()/end(); adaptors like views::filter, views::transform, views::take, and views::reverse compose with | and produce view objects — lightweight, non-owning descriptions of the computation. Nothing is computed until you iterate the view. This means a pipeline of N adaptors requires a single pass through the source data and zero temporary containers, unlike the classic STL approach of chaining algorithms with back_inserter. Ranges also work with infinite generators (views::iota) because of lazy evaluation. The std::ranges:: algorithms (sort, find_if, count_if) accept ranges directly without begin/end boilerplate and are constrained to the appropriate range category via concepts.

🔑 Key line

C++20 ranges pipeline: v | views::filter(pred) | views::transform(fn) | views::take(n) is lazy and zero-copy — the view object is built O(1); elements flow through the pipeline one at a time only when you iterate, with no temporary containers.

The code

#include <algorithm>
#include <ranges>
#include <vector>
std::vector<int> v = {1, 2, 3, 4, 5, 6};
// C++20 ranges pipeline — lazy, composable, readable
auto result = v | std::views::filter([](int x) { return x % 2 == 0; }) |
std::views::transform([](int x) { return x * x; }) | std::views::take(3);
// Lazy: NOTHING is computed until you iterate
for (int n : result) // only NOW each element flows through
std::cout << n << ' '; // output: 4 16 36
// Views are non-owning references — no copies
// Classic alternative needs 2 temp vectors + 2 passes
// Other useful adaptors:
auto dropped = v | std::views::drop(2); // skip first 2
auto reversed = v | std::views::reverse; // reversed view
auto zipped = std::views::zip(v, other); // C++23
auto keys = map | std::views::keys; // map key view

What this lesson walks through

  1. 01The problem with classic STL algorithms
  2. 02Source data — a vector of 6 integers
  3. 03Build the pipeline — nothing computed yet
  4. 04filter(even) — pass only even numbers
  5. 05transform(x*x) — square each passing element
  6. 06take(3) + final output — only first 3 results materialise
  7. 07Key range adaptors every senior C++ engineer knows

With classic STL, filtering then transforming requires two passes and two temporary vectors. The code is also verbose — you lose the data-flow intent in iterator boilerplate. C++20 Ranges solves this with a composable, lazy, zero-copy pipeline.

See it animated — step by step, at your own pace

Unlock the full interactive walkthrough of C++20 Ranges & views — Lazy Zero-Copy Pipelines and 100+ animated C++ interview lessons.

← Previous
C++20 Coroutines — co_yield, co_await, co_return
Next →
C++20 std::span — Non-Owning Contiguous View