std::ranges::size(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’– std::ranges::size(3) πŸ’–

okay bestie, welcome to the C++ Standard Libary manual page for std::ranges::size(3) β€” yes, the manual name has that exact spelling, we are not fixing it, we are respecting the icon behavior πŸ’…. This whole page is about the customization point object that gets you the number of elements in t, in constant time. No cap.


πŸŽ€ NAME πŸŽ€

std::ranges::size β€” std::ranges::size


✨ Synopsis ✨

It's giving "defined in header" energy, so here’s the exact synopsis:

          Defined in header <ranges>
          Defined in header <iterator>
          inline namespace /* unspecified */ {
                                                               (since C++20)
              inline constexpr auto size = /* unspecified */;  (customization
       point object)

          }
          Call signature
          template< class T >

              requires /* see below */                         (since C++20)

          constexpr auto size( T&& t );

Calculates the number of elements in t in constant time. Periodt.

A call to ranges::size is expression-equivalent to:

  1. decay-copy(std::extent_v<T>) (until C++23) or auto(std::extent_v<T>) (since C++23), if T is an array type with a known bound.
  2. Otherwise, decay-copy(t.size()) (until C++23) or auto(t.size()) (since C++23), if ranges::disable_sized_range<std::remove_cv_t<T>> is false, and that expression is valid and has an integer-like type.
  3. Otherwise, decay-copy(size(t)) (until C++23) or auto(size(t)) (since C++23), if ranges::disable_sized_range<std::remove_cv_t<T>> is false, and the converted expression is valid and has an integer-like type, where the meaning of size is established as if by performing argument-dependent lookup only.
  4. Otherwise, /* to-unsigned-like */(ranges::end(t) - ranges::begin(t)), if T models ranges::forward_range and ranges::sentinel_t<T> models std::sized_sentinel_for<ranges::iterator_t<T>>, where /* to-unsigned-like */ denotes an explicit conversion to an unsigned-integer-like type.

In all other cases, a call to ranges::size is ill-formed, which can result in substitution failure when ranges::size(t) appears in the immediate context of a template instantiation. That's the dramatic part 😭.


πŸ¦‹ Notes πŸ¦‹

Whenever ranges::size(e) is valid for an expression e, the return type is integer-like. Slay.

The C++20 standard requires that if the underlying size function call returns a prvalue, the return value is move-constructed from the materialized temporary object. All implementations directly return the prvalue instead. The requirement is corrected by the post-C++20 proposal P0849R8 to match the implementations. iykyk.

The expression ranges::distance(e) can also be used to determine the size of a range e. Unlike ranges::size(e), ranges::distance(e) works even if e is an unsized range, at the cost of having linear complexity in that case. Lowkey useful, highkey a tradeoff.


🌈 Example 🌈

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

int main()
{
    auto v = std::vector<int>{};
    std::cout << "ranges::size(v) == " << std::ranges::size(v) << '\n';

    auto il = {7};     // std::initializer_list
    std::cout << "ranges::size(il) == " << std::ranges::size(il) << '\n';

    int array[]{4, 5}; // array has a known bound
    std::cout << "ranges::size(array) == " << std::ranges::size(array) << '\n';

    static_assert(std::is_signed_v<decltype(std::ranges::size(v))> ==
       false);
}

Output:

ranges::size(v) == 0
ranges::size(il) == 1
ranges::size(array) == 2

🌸 Defect reports 🌸

The following behavior-changing defect reports were applied retroactively to previously published C++ standards. Very "fix it retroactively" of them.

  • DR: P2602R2 Β· Applied to: C++20 Β· Behavior as published: "there's machinery to prohibit certain non-member size found by ADL" Β· Correct behavior: "removed such machinery".

πŸ’œ See also πŸ’œ

  • ranges::ssize β€” returns a signed integer equal to the size of a range (C++20) (customization point object)
  • ranges::sized_range β€” specifies that a range knows its size in constant time (C++20) (concept)
  • ranges::distance β€” returns the distance between an iterator and a sentinel, or between the beginning and end of a range (C++20) (niebloid)
  • size (C++17), ssize (C++20) β€” returns the size of a container or array (function template)

mwah πŸ’‹ this absolute banger came from http://cppreference.com, version 2024.06.10, and the page is std::ranges::size(3) β€” bye bestie, go size something iconic 🫢✨

πŸ“¦ where this page comes from