Something went wrong. Try again.
A Tour of C++ for experienced programmers, as if C++26 is the only version that ever existed.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381<!DOCTYPE HTML><html lang="en" class="light sidebar-visible" dir="ltr"> <head> <!-- Book generated using mdBook --> <meta charset="UTF-8"> <title>Ranges and views - A Tour of C++26</title>
<!-- Custom HTML head -->
<meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon-de23e50b.svg"> <link rel="shortcut icon" href="favicon-8114d1fc.png"> <link rel="stylesheet" href="css/variables-8adf115d.css"> <link rel="stylesheet" href="css/general-e96d0476.css"> <link rel="stylesheet" href="css/chrome-d279d366.css"> <link rel="stylesheet" href="css/print-9e4910d8.css" media="print">
<!-- Fonts --> <link rel="stylesheet" href="fonts/fonts-9644e21d.css">
<!-- Highlight.js Stylesheets --> <link rel="stylesheet" id="mdbook-highlight-css" href="highlight-493f70e1.css"> <link rel="stylesheet" id="mdbook-tomorrow-night-css" href="tomorrow-night-4c0ae647.css"> <link rel="stylesheet" id="mdbook-ayu-highlight-css" href="ayu-highlight-3fdfc3ac.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript --> <script> const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; window.path_to_searchindex_js = "searchindex-7c7963f3.js"; </script> <!-- Start loading toc.js asap --> <script src="toc-0eddcac6.js"></script> </head> <body> <div id="mdbook-help-container"> <div id="mdbook-help-popup"> <h2 class="mdbook-help-title">Keyboard shortcuts</h2> <div> <p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p> <p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p> <p>Press <kbd>?</kbd> to show this help</p> <p>Press <kbd>Esc</kbd> to hide this help</p> </div> </div> </div> <div id="mdbook-body-container"> <!-- Work around some values being stored in localStorage wrapped in quotes --> <script> try { let theme = localStorage.getItem('mdbook-theme'); let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) { localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); }
if (sidebar.startsWith('"') && sidebar.endsWith('"')) { localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1)); } } catch (e) { } </script>
<!-- Set the theme before any content is loaded, prevents flash --> <script> const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme; let theme; try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } if (theme === null || theme === undefined) { theme = default_theme; } const html = document.documentElement; html.classList.remove('light') html.classList.add(theme); html.classList.add("js"); </script>
<input type="checkbox" id="mdbook-sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed --> <script> let sidebar = null; const sidebar_toggle = document.getElementById("mdbook-sidebar-toggle-anchor"); if (document.body.clientWidth >= 1080) { try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { } sidebar = sidebar || 'visible'; } else { sidebar = 'hidden'; sidebar_toggle.checked = false; } if (sidebar === 'visible') { sidebar_toggle.checked = true; } else { html.classList.remove('sidebar-visible'); } </script>
<nav id="mdbook-sidebar" class="sidebar" aria-label="Table of contents"> <!-- populated by js --> <mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox> <noscript> <iframe class="sidebar-iframe-outer" src="toc.html"></iframe> </noscript> <div id="mdbook-sidebar-resize-handle" class="sidebar-resize-handle"> <div class="sidebar-resize-indicator"></div> </div> </nav>
<div id="mdbook-page-wrapper" class="page-wrapper">
<div class="page"> <div id="mdbook-menu-bar-hover-placeholder"></div> <div id="mdbook-menu-bar" class="menu-bar sticky"> <div class="left-buttons"> <label id="mdbook-sidebar-toggle" class="icon-button" for="mdbook-sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="mdbook-sidebar"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></span> </label> <button id="mdbook-theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="mdbook-theme-list"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M371.3 367.1c27.3-3.9 51.9-19.4 67.2-42.9L600.2 74.1c12.6-19.5 9.4-45.3-7.6-61.2S549.7-4.4 531.1 9.6L294.4 187.2c-24 18-38.2 46.1-38.4 76.1L371.3 367.1zm-19.6 25.4l-116-104.4C175.9 290.3 128 339.6 128 400c0 3.9 .2 7.8 .6 11.6c1.8 17.5-10.2 36.4-27.8 36.4H96c-17.7 0-32 14.3-32 32s14.3 32 32 32H240c61.9 0 112-50.1 112-112c0-2.5-.1-5-.2-7.5z"/></svg></span> </button> <ul id="mdbook-theme-list" class="theme-popup" aria-label="Themes" role="menu"> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-default_theme">Auto</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-light">Light</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-rust">Rust</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-coal">Coal</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-navy">Navy</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-ayu">Ayu</button></li> </ul> <button id="mdbook-search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="mdbook-searchbar"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg></span> </button> </div>
<h1 class="menu-title">A Tour of C++26</h1>
<div class="right-buttons"> <a href="print.html" title="Print this book" aria-label="Print this book"> <span class=fa-svg id="print-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg></span> </a>
</div> </div>
<div id="mdbook-search-wrapper" class="hidden"> <form id="mdbook-searchbar-outer" class="searchbar-outer"> <div class="search-wrapper"> <input type="search" id="mdbook-searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="mdbook-searchresults-outer" aria-describedby="searchresults-header"> <div class="spinner-wrapper"> <span class=fa-svg id="fa-spin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M304 48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zm0 416c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM48 304c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm464-48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM142.9 437c18.7-18.7 18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zm0-294.2c18.7-18.7 18.7-49.1 0-67.9S93.7 56.2 75 75s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zM369.1 437c18.7 18.7 49.1 18.7 67.9 0s18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9z"/></svg></span> </div> </div> </form> <div id="mdbook-searchresults-outer" class="searchresults-outer hidden"> <div id="mdbook-searchresults-header" class="searchresults-header"></div> <ul id="mdbook-searchresults"> </ul> </div> </div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM --> <script> document.getElementById('mdbook-sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible'); document.getElementById('mdbook-sidebar').setAttribute('aria-hidden', sidebar !== 'visible'); Array.from(document.querySelectorAll('#mdbook-sidebar a')).forEach(function(link) { link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1); }); </script>
<div id="mdbook-content" class="content"> <main> <h1 id="ranges-and-views"><a class="header" href="#ranges-and-views">Ranges and views</a></h1><h2 id="what-a-view-is"><a class="header" href="#what-a-view-is">What a view is</a></h2><p>A view is a lightweight, non-owning handle over a sequence. It borrows the elements and never allocates memory. The view does not manage the lifetime of its elements. The same principle underlies <code>std::string_view</code> and <code>std::span</code> that were introduced earlier. Both types expose a pointer and a length, and they refuse to copy the data. A range is any object that provides <code>begin()</code> and <code>end()</code> that return iterators. A view is a range that does not own its elements. In other words, every view is a range, but not every range is a view.</p><p>Because a view never allocates, construction is a constant‑time pointer‑plus‑size operation. The compiler can inline it and no heap traffic occurs. The view inherits the lifetime constraints of its underlying storage, so a dangling <code>std::span</code> results if the source is destroyed, which the compiler warns about. Declaring a parameter as <code>std::span<const T></code> also signals that the function reads elements without taking ownership, mirroring <code>std::string_view</code> for read‑only text. This combination of zero‑allocation construction and intent‑driven design reduces accidental copies and clarifies ownership boundaries across API surfaces.</p><p>A view has a precise definition in the standard. A type is a view if it is a range, is cheap to copy or move, and does not own the elements it presents. <code>std::ranges</code> even provides <code>std::ranges::owning_view</code> to wrap an owning container into the view model when an API demands a view but you must keep ownership locally. The inverse, <code>std::ranges::ref_view</code>, wraps a reference to a range you already own. Knowing which wrapper applies prevents both dangling and accidental copies.</p><h2 id="stdviews-adaptors"><a class="header" href="#stdviews-adaptors"><code>std::views</code> adaptors</a></h2><p>In the <code><ranges></code> header, a namespace <code>std::views</code> provides a family of adaptors. Each adaptor returns a new view that lazily transforms the underlying range. The most useful adaptors are listed below.</p><ul><li><code>filter</code>: keeps only elements that satisfy a predicate.</li><li><code>transform</code>: applies a function to each element.</li><li><code>take</code>: stops after a given number of elements.</li><li><code>drop</code>: skips a given number of elements.</li><li><code>reverse</code>: iterates the range in reverse order.</li><li><code>split</code>: splits a range on a delimiter.</li><li><code>iota</code>: generates an infinite arithmetic progression.</li></ul><p>These adaptors compose by piping (<code>|</code>). The pipe operator forwards the left-hand side as the source range to the right-hand adaptor, which returns a new view. Because each adaptor is itself a view, the resulting expression is a chain of lightweight objects that never allocate until the final consumption point.</p><p>The following example builds a pipeline that generates the integers from 1 to 10, keeps the even numbers, squares them, and takes the first three results. It then prints the numbers.</p><pre><code class="language-cpp">#include <ranges>#include <iostream>#include <vector>
int main() { // Generate numbers 1..10, keep evens, square them, take first three. auto rng = std::views::iota(1, 11) // 1..10 (exclusive upper bound) | std::views::filter([](int x){ return x % 2 == 0; }) | std::views::transform([](int x){ return x * x; }) | std::views::take(3); for (int v : rng) { std::cout << v << ' '; } std::cout << '\n';}</code></pre><p>It prints the three even squares <code>4 16 36</code>. The <code>EXPECT</code> string in the build file verifies that these three numbers appear in the output.</p><p>Beyond the basic adaptors, the standard library provides combinators such as <code>views::split</code> for tokenising a string on a delimiter and <code>views::reverse</code> for reverse iteration without copying. The adaptor set also covers structure: <code>views::chunk</code> groups elements into fixed-size subranges, <code>views::slide</code> produces overlapping windows, and <code>views::elements</code> extracts the Nth member of each tuple‑like element (e.g., <code>views::elements<0></code> extracts keys from a range of pairs). For associative containers, <code>views::keys</code> and <code>views::values</code> expose just the key or mapped type without copying. These utilities replace verbose loops and temporary containers with concise pipelines.</p><h2 id="laziness"><a class="header" href="#laziness">Laziness</a></h2><p>Views are evaluated on demand. The pipeline does not create a temporary container after each adaptor. The <code>take(3)</code> adaptor stops the source after three elements have been produced. This property enables short-circuiting of expensive sources.</p><p>Consider a situation where the source is an unbounded range, such as <code>std::views::iota(0)</code>. Without laziness, materialising the whole range requires infinite memory and never terminates. The lazy view evaluates each element only when the downstream consumer asks for it, and the <code>take</code> adaptor caps the evaluation.</p><p>The next example constructs an endless <code>iota</code> range, squares each value, and then takes only the first five results. Even though the source can produce an infinite number of elements, the program terminates after five squares because the view stops early.</p><pre><code class="language-cpp">#include <ranges>#include <iostream>
int main() { // Infinite iota, square each, take first five elements. auto rng = std::views::iota(0) // 0,1,2,... infinite | std::views::transform([](int x){ return x * x; }) | std::views::take(5); for (int v : rng) { std::cout << v << ' '; } std::cout << '\n';}</code></pre><p>The output contains the first five squares <code>0 1 4 9 16</code>. In contrast, a pre-ranges algorithm that first copies the <code>iota</code> range into a <code>std::vector</code> allocates billions of elements before the program must stop. The lazy view avoids that allocation entirely, saving both time and memory.</p><p>Laziness also improves cache behaviour. Each element is produced, transformed, and consumed in a single pass, keeping data in registers and avoiding a second memory pass. The same laziness applies to conditional stops: <code>views::take_while</code> keeps elements while a predicate holds and then halts, and <code>views::drop_while</code> discards until the predicate first fails. Because the adaptors are stateless, chaining <code>drop_while</code> with <code>take_while</code> on a sorted range extracts a contiguous band in one pass without building it.</p><h2 id="materialising-a-view-stdrangesto"><a class="header" href="#materialising-a-view-stdrangesto">Materialising a view: <code>std::ranges::to</code></a></h2><p>Sometimes code needs ownership of the elements produced by a view. The helper <code>std::ranges::to</code> materialises a view into a concrete container. The syntax is <code>view | std::ranges::to<Container>()</code>. The container type must be default-constructible and support <code>push_back</code> or equivalent insertion.</p><p>Materialisation is useful when an algorithm later requires random access, when the data must outlive the original source, or when an API expects an owning container. The operation copies each element exactly once and respects the allocator of the target container.</p><p>The target need not be a <code>std::vector</code>. <code>std::ranges::to</code> accepts any container meeting the insertion requirements, including <code>std::list</code>, <code>std::deque</code>, or a fixed-size <code>std::array</code> when the size is known. An optional allocator argument forwards to the container constructor, so materialisation can use a custom pool without changing the pipeline.</p><p>The following program creates the view <code>iota(1,6)</code>, materialises it into a <code>std::vector</code>, and prints the size of the vector.</p><pre><code class="language-cpp">#include <ranges>#include <iostream>#include <vector>
int main() { auto rng = std::views::iota(1, 6); // 1,2,3,4,5 auto vec = rng | std::ranges::to<std::vector<int>>(); std::cout << "size = " << vec.size() << '\n';}</code></pre><p>The program prints <code>size = 5</code>, confirming that the view was copied into a container of the requested size.</p><h2 id="projections-everywhere"><a class="header" href="#projections-everywhere">Projections everywhere</a></h2><p>Most range adaptors and algorithms accept a <em>projection</em>, a callable that extracts a member from each element. Projections let you avoid writing a lambda for a common operation. The syntax <code>&T::member</code> is a pointer-to-member that the algorithm treats as a projection.</p><p>Projections improve compile-time readability and often enable better inlining because the compiler sees a direct member access instead of a generic lambda capture. They also integrate with concepts that require a <code>std::indirectly_readable</code> predicate. This lets the standard library reason about the operation without executing user code.</p><p>The example below defines a simple <code>Point</code> struct with members <code>x</code> and <code>y</code>. A <code>std::vector<Point></code> is sorted by the <code>x</code> coordinate using the projection <code>&Point::x</code>. The program then prints the sorted <code>x</code> values.</p><pre><code class="language-cpp">#include <algorithm>#include <iostream>#include <vector>
struct Point { int x; int y;};
int main() { std::vector<Point> pts{{3,5},{1,2},{2,4}}; // Sort by x using a projection std::ranges::sort(pts, {}, &Point::x); for (const auto& p : pts) { std::cout << p.x << ' '; } std::cout << '\n';}</code></pre><p>The output <code>1 2 3</code> demonstrates that the projection eliminated the need for a custom comparator.</p><p>Beyond sorting, any algorithm that accepts a projection can use the member‑pointer form. <code>std::ranges::find(v, value, &T::key)</code> searches a range of objects for a specific key without a bespoke lambda. The same member‑pointer projection works on associative ranges through <code>views::values</code> and <code>views::keys</code>. For example, <code>m | std::views::values</code> yields the integers from a <code>std::map<std::string, int></code> directly. These patterns appear throughout the standard library and eliminate boilerplate code.</p><h2 id="stdranges-algorithms-versus-pre-ranges-algorithms"><a class="header" href="#stdranges-algorithms-versus-pre-ranges-algorithms"><code>std::ranges</code> algorithms versus pre-ranges algorithms</a></h2><p>The range algorithms in <code>std::ranges</code> operate directly on any range, including views. They return iterators that refer to the original elements, so no copying occurs. The pipe syntax composes algorithms with adaptors. This makes the intent clear and the code compact.</p><p>The pre-ranges algorithmic style often required explicit iterator arguments, temporary containers, and separate calls to <code>std::find</code> or <code>std::count</code>. The range version can operate on a filtered view without materialising the intermediate sequence.</p><p>The next program filters a <code>std::vector<int></code> for even numbers and then counts them using <code>std::ranges::count_if</code>. The count is printed.</p><pre><code class="language-cpp">#include <algorithm>#include <iostream>#include <vector>#include <ranges>
int main() { std::vector<int> data{1,2,3,4,5,6}; auto evens = data | std::views::filter([](int x){ return x % 2 == 0; }); auto count = std::ranges::count_if(evens, [](int){ return true; }); // count elements in view std::cout << "evens = " << count << '\n';}</code></pre><p>The expected output <code>evens = 3</code> shows that the algorithm works on the filtered view without materialising a new container.</p><p>Range algorithms also accept a projection argument, mirroring the adaptor behaviour. For example, <code>std::ranges::sort(v, {}, &T::member)</code> sorts a range of structures by a field without an explicit comparator lambda. This uniformity simplifies generic code that works with both plain values and aggregates.</p><p>Reduction joins the model as well. <code>std::ranges::fold_left</code> and <code>std::ranges::fold_right</code> accumulate a range with an initial value and a binary operation, returning the combined result rather than writing into a destination. They pair naturally with a filter and a transform, so the filter-map-reduce pattern from the algorithms chapter becomes one expression.</p><h2 id="custom-views-and-stdrange_adaptor_closure"><a class="header" href="#custom-views-and-stdrange_adaptor_closure">Custom views and <code>std::range_adaptor_closure</code></a></h2><p>Advanced users can create reusable pipelines by defining a <em>range adaptor closure</em>. A closure is a callable that returns a view when applied to a range. The closure can be used in a pipe expression just like the built-in adaptors.</p><p>Defining a closure typically involves a generic lambda that captures any configuration parameters and returns a composition of existing adaptors. Because the closure returns a <em>closure object</em> (<code>std::range_adaptor_closure</code>), the compiler treats it as another adaptor, preserving laziness.</p><p>The example below defines a simple adaptor <code>twice</code> that multiplies each element by two. The adaptor is expressed as a generic lambda that returns a <code>transform</code> view. The program creates an <code>iota</code> range, pipes it through <code>twice</code>, and prints the results.</p><pre><code class="language-cpp">#include <ranges>#include <iostream>
// A reusable, pipeable adaptor that doubles each element.struct Twice : std::ranges::range_adaptor_closure<Twice> { template <std::ranges::viewable_range R> auto operator()(R&& r) const { return std::views::transform(std::forward<R>(r), [](int x) { return x * 2; }); }};
inline constexpr Twice twice;
int main() { auto rng = std::views::iota(1, 5) | twice; // 1..4 doubled -> 2 4 6 8 for (int v : rng) { std::cout << v << ' '; } std::cout << '\n';}</code></pre><p>The output <code>2 4 6 8</code> confirms that the custom adaptor behaved like a built-in view. Readers can extend this pattern to more sophisticated pipelines, such as a <code>prime_filter</code> that composes <code>filter</code> with a deterministic primality test. Because the closure is a compile-time object, the optimizer can erase the intermediate layers entirely.</p><p>A view lives only as long as its source. Returning a view to a local container or temporary yields a dangling view, which the compiler warns about (see chapter 07). Because the pipeline composes at compile time, the compiler can collapse multiple adaptor layers into a single loop, achieving speed comparable to hand‑written loops while preserving readability.</p><h2 id="try-this"><a class="header" href="#try-this">Try this</a></h2><p>Build a pipeline that takes <code>std::views::iota(1, n)</code>, keeps only the multiples of 3, squares each kept value, takes the first 5 results, and prints them. The program must compile with the book’s standard settings and must run without allocating an intermediate container.</p><p>No solution is provided. The reader must write the code, register it as a <code>book_example</code>, and verify that the output contains five numbers.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation"> <!-- Mobile navigation buttons --> <a rel="prev" href="ch12-algorithms.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span> </a>
<a rel="next prefetch" href="ch14-callables-type-erasure.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span> </a>
<div style="clear: both"></div> </nav> </div> </div>
<nav class="nav-wide-wrapper" aria-label="Page navigation"> <a rel="prev" href="ch12-algorithms.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span> </a>
<a rel="next prefetch" href="ch14-callables-type-erasure.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span> </a> </nav>
</div>
<template id=fa-eye><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></template> <template id=fa-eye-slash><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg></span></template> <template id=fa-copy><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg></span></template> <template id=fa-play><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg></span></template> <template id=fa-clock-rotate-left><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9V168c0 13.3 10.7 24 24 24H134.1c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24V256c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65V152c0-13.3-10.7-24-24-24z"/></svg></span></template>
<script> window.playground_copyable = true; </script>
<script src="elasticlunr-ef4e11c1.min.js"></script> <script src="mark-09e88c2c.min.js"></script> <script src="searcher-09f2665d.js"></script>
<script src="clipboard-1626706a.min.js"></script> <script src="highlight-abc7f01d.js"></script> <script src="book-609e4cb8.js"></script>
<!-- Custom JS scripts -->
</div> </body></html>