std::ranges::begin(3)

๐Ÿ“ฆ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

okay so this is the std::ranges::begin(3) page from the C++ Standard Libary manpage โ€” yes, thatโ€™s the manual name, typo and all ๐Ÿ’€๐Ÿ’–.

๐ŸŒธ NAME ๐ŸŒธ

std::ranges::begin - std::ranges::begin โ€” bestie, thatโ€™s literally the whole NAME entry, and itโ€™s iconic in a minimal way ๐Ÿซถ.

โœจ Synopsis โœจ

okay so hereโ€™s the setup, and itโ€™s defined in two headers:

Defined in header <ranges>
Defined in header <iterator>
inline namespace /* unspecified */ {

    inline constexpr /* unspecified */ begin = /*       (since C++20)
unspecified */;
 (customization point object)

}
Call signature
template< class T >

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

constexpr std::input_or_output_iterator auto begin(
T&& t );

This thing returns an iterator to the first element of the argument. No cap, thatโ€™s the whole vibe โœจ.

Thereโ€™s also a diagram in the original: range-begin-end.svg โ€” visual era ๐Ÿฆ‹.

If the argument is an lvalue or ranges::enable_borrowed_range<std::remove_cv_t<T>> is true, then a call to ranges::begin is expression-equivalent to:

  1. t + 0 if t has an array type.
    • If std::remove_all_extents_t<std::remove_reference_t<T>> is incomplete, then the call to ranges::begin is ill-formed, no diagnostic required.
  2. Otherwise, decay-copy(t.begin()) (until C++23), auto(t.begin()) (since C++23) โ€” if that expression is valid and its type models std::input_or_output_iterator.
  3. Otherwise, decay-copy(begin(t)) (until C++23), auto(begin(t)) (since C++23) โ€” if T is a class or enumeration type, that expression is valid and its type models std::input_or_output_iterator, where the meaning of begin is established as if by performing argument-dependent lookup only.

In all other cases, a call to ranges::begin is ill-formed, which can result in substitution failure when the call appears in the immediate context of a template instantiation.

๐Ÿง  Notes ๐Ÿง 

If the argument is an rvalue (i.e. T is an object type) and ranges::enable_borrowed_range<std::remove_cv_t<T>> is false, the call to ranges::begin is ill-formed, which also results in substitution failure.

The return type models std::input_or_output_iterator in all cases.

The C++20 standard requires that if the underlying begin 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.

๐Ÿ’ป Example ๐Ÿ’ป

// Run this code

#include <cassert>
#include <ranges>
#include <vector>

int main()
{
    std::vector v{3, 1, 4};
    auto vi = std::ranges::begin(v);
    auto vci = std::ranges::cbegin(v);
    assert(*vi == 3 and *vi == *vci);
    ++vi;
    ++vci; // OK: vci is modifiable object
    *vi = 42; // OK: vi points to mutable element
    // *vci = 13; // Error: vci points to immutable element

    int a[]{-5, 10, 15};
    auto ai = std::ranges::begin(a); // works with C-arrays as well
    assert(*ai == -5);
    *ai = 42; // OK
}

๐Ÿฉน Defect reports ๐Ÿฉน

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

  • DR P2602R2, applied to C++20 โ€” behavior as published: โ€œthereโ€™s machinery to prohibit certain non-member begin found by ADLโ€; correct behavior: โ€œremoved such machineryโ€.

๐Ÿ‘€ See also ๐Ÿ‘€

  • ranges::cbegin โ€” returns an iterator to the beginning of a read-only range. (C++20) (customization point object)
  • begin (C++11), cbegin (C++14) โ€” returns an iterator to the beginning of a container or array. (function template)

source/version + date sign-off: http://cppreference.com, 2024.06.10, page std::ranges::begin(3) โ€” byeee, go read your iterators and hydrate ๐Ÿ’œโœจ

๐Ÿ“ฆ where this page comes from