C++ ranges
lazy evaluation
programming
C++ views
software development

Lazy combinations of c ranges view

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

C++20 introduced the Ranges library, which provides composable, lazy views for transforming and filtering data without creating intermediate containers. Views are lightweight wrappers that compute elements on-demand — no allocation, no copying. By combining (composing) multiple views, you can build complex data pipelines that process elements only when iterated, leading to significant performance and memory improvements.

What Makes Views Lazy?

A view does not execute its transformation when created. It stores the recipe and applies it only when you iterate:

cpp
1#include <ranges>
2#include <vector>
3#include <iostream>
4
5std::vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
6
7// No computation happens here — just builds the pipeline
8auto pipeline = nums
9| std::views::filter([](int n) { return n % 2 == 0; }) | std::views::transform([](int n) { return n * n; }); // Computation happens HERE, element by element for (int val : pipeline) { std::cout << val << " ";  // 4 16 36 64 100 } ``` No intermediate vector of even numbers is created. Each element flows through the full pipeline one at a time. ## Core Views in C++20 ### Filtering ```cpp auto evens = nums | std::views::filter([](int n) { return n % 2 == 0; }); // Yields: 2, 4, 6, 8, 10 ``` ### Transforming ```cpp auto squares = nums | std::views::transform([](int n) { return n * n; }); // Yields: 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 ``` ### Taking and Dropping ```cpp auto first3 = nums | std::views::take(3);       // 1, 2, 3 auto skip3 = nums | std::views::drop(3);         // 4, 5, 6, 7, 8, 9, 10 auto while_small = nums | std::views::take_while([](int n) { return n < 5; }); // 1, 2, 3, 4 ``` ### Reversing ```cpp auto reversed = nums | std::views::reverse;      // 10, 9, 8, ..., 1 ``` ### Iota (Generate Sequences) ```cpp // Infinite sequence starting at 0 auto naturals = std::views::iota(0); // First 10 even numbers auto first10even = std::views::iota(0) | std::views::filter([](int n) { return n % 2 == 0; }) | std::views::take(10); // 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 ``` ## Composing Multiple Views The pipe operator (`|`) chains views into complex lazy pipelines: ```cpp #include <ranges> #include <vector> #include <string> struct Employee { std::string name; int department; double salary; }; std::vector<Employee> employees = { /* ... */ }; // Find names of top-paid engineers auto top_engineers = employees | std::views::filter([](const Employee& e) { return e.department == 42;              // engineering dept }) | std::views::filter([](const Employee& e) { return e.salary > 100000;               // high salary }) | std::views::transform([](const Employee& e) { return e.name;                          // extract name }) | std::views::take(5);                      // limit to 5 for (const auto& name : top_engineers) { std::cout << name << "\n"; } ``` This processes each employee through all stages before moving to the next — no intermediate vectors are allocated. ## Benefits of Lazy Composition * **Performance Improvement**: Because operations are deferred, elements are processed only when they are accessed. No wasted computation on elements you never use. * **Reduced Memory Footprint**: Since operations are performed on-the-fly, memory allocation for intermediate results is minimized. A pipeline over 1 million elements uses O(1) extra memory. * **Enhanced Composability**: By combining lazy operations, complex transformations can be built from simple, reusable parts. * **Short-circuit evaluation**: `take(5)` stops the entire pipeline after 5 matches — upstream filters/transforms are never applied to remaining elements. ## C++23 Additions C++23 adds more view combinators: ```cpp // std::views::zip — combine multiple ranges auto zipped = std::views::zip(names, ages); // Yields pairs: ("Alice", 30), ("Bob", 25), ... // std::views::enumerate — index + element for (auto [i, val] : nums | std::views::enumerate) { std::cout << i << ": " << val << "\n"; } // std::views::chunk — split into groups auto pairs = nums | std::views::chunk(2); // {1,2}, {3,4}, {5,6}, ... // std::views::slide — sliding window auto windows = nums | std::views::slide(3); // {1,2,3}, {2,3,4}, {3,4,5}, ... ``` ## Materializing Views into Containers Views are lazy — to store results, convert to a container: ```cpp // C++23: std::ranges::to auto result = pipeline | std::ranges::to<std::vector>(); // C++20: manual construction auto view = nums | std::views::filter([](int n) { return n > 5; }); std::vector<int> result(view.begin(), view.end()); ``` ## Common Pitfalls * **Dangling references**: Views do not own data. If the underlying container is destroyed or moved, the view becomes dangling. Ensure the source outlives the view. * **Multiple iterations**: Some views (like `filter`) recompute on each iteration. If the predicate is expensive, cache results by materializing to a container after the first pass. * **Not all views are bidirectional**: `filter` views are forward-only because the predicate must be evaluated sequentially. You cannot use `views::reverse` after `views::filter`. * **Compilation errors**: Template-heavy ranges code produces notoriously verbose error messages. Start with simple pipelines and add stages one at a time. * **Compiler support**: Full C++20 ranges support requires GCC 10+, Clang 15+, or MSVC 19.29+. C++23 features require newer compilers (GCC 13+, Clang 17+). ## Summary * C++20 views are lazy — they compute elements on-demand without allocating intermediate containers * Use the pipe operator (`|`) to compose `filter`, `transform`, `take`, `drop`, and other views * Lazy pipelines use O(1) extra memory and short-circuit when possible * Views do not own data — ensure the source container outlives the view * C++23 adds `zip`, `enumerate`, `chunk`, `slide`, and `std::ranges::to` for materialization

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.