CodeNebula
C++20stladvanced

std::ranges::forward_range (C++20 Addition)

C++20 · The Big Four · Compiler flag: -std=c++20

Explanation

Concept for ranges supporting multi-pass forward iteration. Iterators can be copied and independently advanced, enabling algorithms that need multiple passes over data.

Real-World Scenario

Implement a pattern-matching algorithm on a linked list of tokens that requires looking ahead and backtracking.

Quick Snippet

snippet.cpp
#include <ranges>

template<std::ranges::forward_range R>
bool has_duplicates(R&& r) {
    for (auto it = std::ranges::begin(r); it != std::ranges::end(r); ++it)
        for (auto jt = std::next(it); jt != std::ranges::end(r); ++jt)
            if (*it == *jt) return true;
    return false;
}

Full Example

ranges_forward_range.cpp
// CodeNebula - C++20 Example: std::ranges::forward_range Concept
// Compile: g++ -std=c++20 -Wall -Wextra -o example ranges_forward_range.cpp

#include <ranges>
#include <vector>
#include <forward_list>
#include <list>
#include <algorithm>
#include <iostream>

// std::ranges::forward_range requires multi-pass iteration,
// meaning you can iterate over the range multiple times and
// save/restore iterator positions.

// Find duplicates - requires multi-pass (forward_range)
template <std::ranges::forward_range R>
bool has_duplicates(R&& r) {
    for (auto it = std::ranges::begin(r); it != std::ranges::end(r); ++it) {
        for (auto jt = std::next(it); jt != std::ranges::end(r); ++jt) {
            if (*it == *jt) return true;
        }
    }
    return false;
}

// Check if range is palindrome - requires forward_range
template <std::ranges::forward_range R>
    requires std::equality_comparable<std::ranges::range_value_t<R>>
bool is_palindrome(R&& r) {
    auto collected = std::vector(std::ranges::begin(r), std::ranges::end(r));
    auto sz = collected.size();
    for (std::size_t i = 0; i < sz / 2; ++i) {
        if (collected[i] != collected[sz - 1 - i]) return false;
    }
    return true;
}

int main() {
    // Forward-iterable containers
    static_assert(std::ranges::forward_range<std::vector<int>>);
    static_assert(std::ranges::forward_range<std::forward_list<int>>);
    static_assert(std::ranges::forward_range<std::list<int>>);

    std::vector<int> nums = {3, 1, 4, 1, 5};
    std::cout << "nums has duplicates: " << std::boolalpha
              << has_duplicates(nums) << "\n";

    std::vector<int> unique_nums = {1, 2, 3, 4, 5};
    std::cout << "unique_nums has duplicates: "
              << has_duplicates(unique_nums) << "\n";

    // forward_list is a forward_range but NOT bidirectional
    std::forward_list<int> flist = {1, 2, 3, 2, 1};
    std::cout << "flist is palindrome: " << is_palindrome(flist) << "\n";

    // Views can also be forward ranges
    auto filtered = nums | std::views::filter([](int x) { return x > 2; });
    static_assert(std::ranges::forward_range<decltype(filtered)>);
    std::cout << "Filtered has duplicates: "
              << has_duplicates(filtered) << "\n";

    // Using ranges::search (requires forward_range)
    std::vector<int> pattern = {4, 1};
    auto result = std::ranges::search(nums, pattern);
    std::cout << "Pattern found at position: "
              << std::ranges::distance(nums.begin(), result.begin()) << "\n";

    return 0;
}
Run command
g++ -std=c++20 -Wall -Wextra -o example ranges_forward_range.cpp