CodeNebula
C++20stladvanced

Range Query CPOs: std::ranges::size / ssize / empty / data / cdata (C++20 Addition)

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

Explanation

CPOs for querying range properties. `size` returns the number of elements, `ssize` returns a signed size, `empty` checks for emptiness, and `data`/`cdata` obtain a pointer to contiguous storage.

Real-World Scenario

Implement a buffer upload function that queries size and raw data pointer portably across std::vector, std::array, and std::span.

Quick Snippet

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

template<std::ranges::contiguous_range R>
void upload(R&& r) {
    if (std::ranges::empty(r)) return;
    auto* ptr = std::ranges::data(r);
    auto count = std::ranges::ssize(r);
    // transmit(ptr, count);
}

Full Example

ranges_utils.cpp
// CodeNebula - C++20 Example: Range Utilities (ranges::size/ssize/empty/data/cdata)
// Compile: g++ -std=c++20 -Wall -Wextra -o example ranges_utils.cpp

#include <ranges>
#include <vector>
#include <array>
#include <string>
#include <list>
#include <span>
#include <iostream>

// std::ranges provides utility CPOs: size(), ssize(), empty(),
// data(), and cdata() for uniform access to range properties.

template <std::ranges::sized_range R>
void print_size_info(const R& r, const char* name) {
    std::cout << name << ": size=" << std::ranges::size(r)
              << ", ssize=" << std::ranges::ssize(r)
              << ", empty=" << std::boolalpha << std::ranges::empty(r) << "\n";
}

template <std::ranges::contiguous_range R>
void print_data_info(const R& r, const char* name) {
    auto ptr = std::ranges::data(r);
    auto cptr = std::ranges::cdata(r);
    std::cout << name << ": data points to first element = "
              << *ptr << ", cdata = " << *cptr << "\n";
}

int main() {
    std::vector<int> vec = {10, 20, 30, 40, 50};
    std::vector<int> empty_vec;
    std::array<double, 3> arr = {1.1, 2.2, 3.3};
    std::string str = "Hello";
    int c_arr[] = {7, 8, 9};

    // Size and empty
    std::cout << "=== Size Info ===\n";
    print_size_info(vec, "vector<int>");
    print_size_info(empty_vec, "empty vector");
    print_size_info(arr, "array<double,3>");
    print_size_info(str, "string");
    print_size_info(c_arr, "int[3]");

    // ssize returns a signed type, useful for avoiding signed/unsigned issues
    auto sz = std::ranges::ssize(vec);
    for (decltype(sz) i = sz - 1; i >= 0; --i) {
        // Safe: no unsigned underflow
    }
    std::cout << "\nssize type is signed: "
              << std::is_signed_v<decltype(sz)> << "\n";

    // Data pointer access for contiguous ranges
    std::cout << "\n=== Data Pointers ===\n";
    print_data_info(vec, "vector<int>");
    print_data_info(arr, "array<double,3>");
    print_data_info(str, "string");
    print_data_info(c_arr, "int[3]");

    // empty() works on all ranges
    std::cout << "\n=== Empty Check ===\n";
    std::cout << "vec empty: " << std::ranges::empty(vec) << "\n";
    std::cout << "empty_vec empty: " << std::ranges::empty(empty_vec) << "\n";

    // Works with views
    auto view = vec | std::views::take(0);
    std::cout << "take(0) empty: " << std::ranges::empty(view) << "\n";
    return 0;
}
Run command
g++ -std=c++20 -Wall -Wextra -o example ranges_utils.cpp