Ranges & Views (C++20)

Composable, lazy data transformations using the C++20 ranges library

The Problem with Traditional Loops

Traditional C++ requires verbose loops and temporary containers for data transformations.

// Traditional approach: verbose and error-prone
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// Step 1: Filter evens
std::vector<int> evens;
for (int n : numbers) {
    if (n % 2 == 0) {
        evens.push_back(n);
    }
}

// Step 2: Transform to squares
std::vector<int> squares;
for (int n : evens) {
    squares.push_back(n * n);
}

// Step 3: Take first 3
std::vector<int> result;
for (size_t i = 0; i < std::min(squares.size(), size_t{3}); ++i) {
    result.push_back(squares[i]);
}

// Issues: Multiple allocations, verbose, hard to read intent

C++20: Ranges Pipeline

The ranges library provides composable, lazy operations using the pipe operator.

#include <ranges>
#include <vector>

namespace rv = std::views;

std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

auto result = numbers
    | rv::filter([](int n) { return n % 2 == 0; })
    | rv::transform([](int n) { return n * n; })
    | rv::take(3);

// No intermediate containers! Each element flows through the pipeline.
for (int n : result) {
    std::cout << n << " ";  // Output: 4 16 36
}

Standard Views

ViewDescription
filterKeep elements matching predicate
transformApply function to each element
takeFirst N elements
dropSkip first N elements
reverseReverse order

Lazy Evaluation

Views do not compute until you iterate. This enables efficient composition.

std::vector<int> data(1'000'000);

auto pipeline = data
    | rv::filter([](int n) { return n % 2 == 0; })
    | rv::transform([](int n) { return n * n; })
    | rv::take(10);

// Only processes elements until 10 even numbers are found
for (int n : pipeline) {
    std::cout << n << " ";
}