CodeNebula
C++20stladvanced

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

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

Explanation

Concept for ranges that can report their size in constant time via `std::ranges::size()`. Not all ranges know their size (e.g., filtered views), so this concept lets algorithms optimize when size is available.

Real-World Scenario

Pre-allocate an output buffer to the exact size of an input range before processing.

Quick Snippet

snippet.cpp
#include <ranges>
#include <vector>

template<std::ranges::sized_range R>
auto to_vector(R&& r) {
    std::vector<std::ranges::range_value_t<R>> result;
    result.reserve(std::ranges::size(r));
    for (auto&& elem : r) result.push_back(elem);
    return result;
}

Full Example

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

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

// std::ranges::sized_range requires O(1) size via std::ranges::size().
// This means the range knows its element count without iterating.

// Reserve and copy - efficient only when we know the size upfront
template <std::ranges::sized_range R>
auto to_vector(R&& r) {
    using T = std::ranges::range_value_t<R>;
    std::vector<T> result;
    result.reserve(std::ranges::size(r));
    for (auto&& elem : r) {
        result.push_back(std::forward<decltype(elem)>(elem));
    }
    return result;
}

// Print range info including size
template <std::ranges::sized_range R>
void print_info(const R& r) {
    std::cout << "Size: " << std::ranges::size(r) << " | Elements: ";
    for (const auto& elem : r) {
        std::cout << elem << " ";
    }
    std::cout << "\n";
}

int main() {
    // Most containers are sized ranges
    static_assert(std::ranges::sized_range<std::vector<int>>);
    static_assert(std::ranges::sized_range<std::list<int>>);
    static_assert(std::ranges::sized_range<std::set<int>>);
    static_assert(std::ranges::sized_range<int[5]>);

    // forward_list does NOT have O(1) size
    static_assert(!std::ranges::sized_range<std::forward_list<int>>);

    std::vector<int> vec = {10, 20, 30, 40, 50};
    print_info(vec);

    std::list<int> lst = {1, 2, 3};
    print_info(lst);

    // iota_view with bounds is sized
    auto iota = std::views::iota(1, 11);
    static_assert(std::ranges::sized_range<decltype(iota)>);
    std::cout << "iota size: " << std::ranges::size(iota) << "\n";

    // Convert a view to vector efficiently
    auto squares = iota | std::views::transform([](int x) { return x * x; });
    auto sq_vec = to_vector(squares);
    std::cout << "Squares: ";
    for (int v : sq_vec) std::cout << v << " ";
    std::cout << "\n";

    // take_view produces a sized_range from a sized source
    auto first3 = vec | std::views::take(3);
    static_assert(std::ranges::sized_range<decltype(first3)>);
    std::cout << "Take(3) size: " << std::ranges::size(first3) << "\n";

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