Skip to content
C++ Basics: Compose Lazy Filter and Transform Views

C++ Basics: Compose Lazy Filter and Transform Views

November 2, 2026

Build a C++20 range pipeline without creating an intermediate result vector.

Prepare a scratch directory

Tested on Linux x86_64 with GCC 14.2.0. Install a C++20-capable compiler and standard-library development headers, with g++ on PATH. You also need Bash, a text editor, and the mktemp, rm, and rmdir utilities. No third-party library is required.

Keep the same terminal open. Stop if setup fails, before saving the source:

start_directory="$PWD"
work_directory="$(mktemp -d)" || exit 1
cd -- "$work_directory" || exit 1

Run the example

Save this as lazy-filter-transform-demo.cpp:

#include <iostream>
#include <ranges>
#include <vector>

int main() {
    std::vector<int> values{1, 2, 3, 4};
    auto doubled_even_values = values
        | std::views::filter([](int value) { return value % 2 == 0; })
        | std::views::transform([](int value) { return value * 2; });

    values[1] = 6;  // Change the source before any iteration begins.
    std::cout << "View:";
    for (int value : doubled_even_values) {
        std::cout << ' ' << value;
    }
    std::cout << "\nSource:";
    for (int value : values) {
        std::cout << ' ' << value;
    }
    std::cout << '\n';
}

Compile and run it. The second command runs only after compilation succeeds:

g++ -std=c++20 -Wall -Wextra -Werror -pedantic lazy-filter-transform-demo.cpp -o lazy-filter-transform-demo &&
./lazy-filter-transform-demo

Observed output:

View: 12 8
Source: 1 6 3 4

Read the result

The pipeline stores a description of the computation rather than a vector of answers. Changing two to six before iteration means the view yields twelve and eight. Transformation does not overwrite the source, which still holds six and four.

Apply it carefully

Keep the source alive while using this view. Do not mutate the vector while traversing it: reallocation can invalidate iterators, and filter views may cache their first match. The source change here occurs before the first begin() call and preserves element count. Keep predicates and transformations free of state-dependent side effects; a view is not a promise of one invocation per element across arbitrary uses.

The C++ working draft describes the relevant library rules. This example uses only C++20 facilities, even though the linked draft also documents newer additions.

Clean up

Remove only the source and executable created here, then remove the empty practice directory:

rm -- lazy-filter-transform-demo.cpp lazy-filter-transform-demo
cd -- "$start_directory" || exit 1
rmdir -- "$work_directory"
unset start_directory work_directory

If the directory is not empty, inspect its remaining contents before removing anything else.

Acknowledgements

This post was created with assistance from AI.

Last updated on