std::ranges...s::drop_view(3)

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

πŸ’– NAME πŸ’–

std::ranges::views::drop, std::ranges::drop_view β€” the NAME line repeats it as std::ranges::views::drop,std::ranges::drop_view, because why not. This is the std::ranges...s::drop_view(3) page from the C++ Standard Libary manual (their spelling, not mine 😭).


πŸ¦‹ Synopsis πŸ¦‹

Okay so this whole thing lives in the header <ranges> β€” that's the include, bestie. The page shows two things, (1) and (2), both since C++20.

template< ranges::view V >

class drop_view
(1) (since C++20)

    : public ranges::view_interface<drop_view<V>>
namespace views {

    inline constexpr /* unspecified */ drop = /* unspecified */;
(2) (since C++20)

}

πŸ“ž Call signature πŸ“ž

Here's the call signature section in all its template-y glory:

template< ranges::viewable_range R >

    requires /* see below */
(since C++20)
constexpr ranges::view auto

    drop( R&& r, ranges::range_difference_t<R> count );

and then this other signature, with the closing-parenthesis situation exactly as the page has it β€” don't come for me πŸ’€:

template< class DifferenceType >
constexpr /* range adaptor closure */ drop( DifferenceType&& count
(since C++20)
);

So what do the numbers mean? Say less:

  • 1) A range adaptor consisting of elements of the underlying sequence, skipping the first N elements.
  • 2) RangeAdaptorObject. Given T is std::remove_cvref_t<decltype((e))> and D is ranges::range_difference_t<decltype((e))>), the expression views::drop(e, f) is expression-equivalent to:
    • ((void)f, decay-copy(e)), if T is a ranges::empty_view, except that the evaluations of e and f are indeterminately sequenced;
    • otherwise, T(ranges::begin(e) + inc, ranges::end(e), /* to-unsigned-like */(ranges::distance(e) - inc)), if T is a specialization of ranges::subrange that models both random_access_range and sized_range, and T needs to store the size (see ranges::subrange::subrange for details), where inc is std::min<D>(ranges::distance(e), f);
    • otherwise, U(ranges::begin(e) + inc, ranges::end(e)), if T is a specialization of std::span, std::basic_string_view, ranges::iota_view, or ranges::subrange that models both random_access_range and sized_range, where U is
      • std::span<typename T::element_type>, if T is a specialization of std::span;
      • T otherwise;
    • otherwise, if T is a specialization of ranges::repeat_view:
      • views::repeat(*e.value_, ranges::distance(e) - inc), if T models (since C++23) sized_range; in such case e is evaluated only once;
      • ((void)e, auto(f)) otherwise, except that the evaluations of e and f are indeterminately sequenced;
    • otherwise, drop_view(e, f).

In all cases, decltype((f)) must model std::convertible_to<D>.

Vibe check on concepts: drop_view models the concepts contiguous_range, random_access_range, bidirectional_range, forward_range, input_range, common_range, and sized_range when the underlying view V models respective concepts.


🌸 Member functions 🌸

Here's the whole member-function roster, with the C++ version and public-member-function energy kept intact:

  • constructor (C++20) β€” constructs a drop_view. (public member function)
  • base (C++20) β€” returns a copy of the underlying (adapted) view. (public member function)
  • begin (C++20) β€” returns an iterator to the beginning. (public member function)
  • end (C++20) β€” returns an iterator or a sentinel to the end. (public member function)
  • size (C++20) β€” returns the number of elements. Provided only if the underlying (adapted) range satisfies sized_range. (public member function)

πŸ‘‘ Inherited from std::ranges::view_interface πŸ‘‘

  • empty (C++20) β€” returns whether the derived view is empty. Provided if it satisfies sized_range or forward_range. (public member function of std::ranges::view_interface<D>)
  • cbegin (C++23) β€” returns a constant iterator to the beginning of the range. (public member function of std::ranges::view_interface<D>)
  • cend (C++23) β€” returns a sentinel for the constant iterator of the range. (public member function of std::ranges::view_interface<D>)
  • operator bool (C++20) β€” returns whether the derived view is not empty. Provided if ranges::empty is applicable to it. (public member function of std::ranges::view_interface<D>)
  • data (C++20) β€” gets the address of derived view's data. Provided if its iterator type satisfies contiguous_iterator. (public member function of std::ranges::view_interface<D>)
  • front (C++20) β€” returns the first element in the derived view. Provided if it satisfies forward_range. (public member function of std::ranges::view_interface<D>)
  • back (C++20) β€” returns the last element in the derived view. Provided if it satisfies bidirectional_range and common_range. (public member function of std::ranges::view_interface<D>)
  • operator[] (C++20) β€” returns the n^th element in the derived view. Provided if it satisfies random_access_range. (public member function of std::ranges::view_interface<D>)

πŸŽ€ Deduction guides πŸŽ€

Yup, this section exists on the page. The page doesn't spell out individual guides here, so we're not making anything up β€” just noting the section is present. πŸ’…


✨ Helper templates ✨

The helper-template part, preserved exactly:

template<class T>

inline constexpr bool
(since C++20)
enable_borrowed_range<std::ranges::drop_view<T>> =

    std::ranges::enable_borrowed_range<T>;

This specialization of std::ranges::enable_borrowed_range makes drop_view satisfy borrowed_range when the underlying view satisfies it.


πŸ“ Example πŸ“

Run this code β€” actual executable example, copied exactly because duh:

// Run this code

#include <iostream>
#include <ranges>

int main()
{
    const auto nums = {1, 2, 3, 4, 5, 6, 7};

    std::cout << "drop " << 2 << ": ";
    for (int i : std::ranges::drop_view{nums, 2})
        std::cout << i << ' ';
    std::cout << '\n';

    std::cout << "drop " << 3 << ": ";
    for (int i : nums | std::views::drop(3))
        std::cout << i << ' ';
    std::cout << '\n';

    std::cout << "drop " << 4 << ": ";
    for (int i : std::views::iota(1, 8) | std::views::drop(4))
        std::cout << i << ' ';
    std::cout << '\n';

    // Note that dropping more than the number of elements is OK:
    for (int dp : {5, 6, 7, 890, 100500})
    {
        std::cout << "drop " << dp << ": ";
        for (int i : std::views::iota(1, 8) | std::views::drop(dp))
            std::cout << i << ' ';
        std::cout << '\n';
    }
}

πŸ’… Output πŸ’…

And the output is literally:

drop 2: 3 4 5 6 7
drop 3: 4 5 6 7
drop 4: 5 6 7
drop 5: 6 7
drop 6: 7
drop 7:
drop 890:
drop 100500:

🧚 Defect reports 🧚

The following behavior-changing defect reports were applied retroactively to previously published C++ standards. Here's the DR tea, unrolled:

  • LWG 3407 β€” applied to C++20. Behavior as published: views::drop sometimes fails to construct a sized random access range. Correct behavior: the construction is adjusted so that it is always valid.
  • LWG 3494 β€” applied to C++20. Behavior as published: drop_view was never a borrowed_range. Correct behavior: it is a borrowed_range if its underlying view is one.

🌈 See also 🌈

  • ranges::drop_while_view, views::drop_while (C++20) β€” a view consisting of the elements of another view, skipping the initial subsequence of elements until the first element where the predicate returns false. (class template) (range adaptor object)

Okay that's the whole manual page, bestie 🫢✨. Source/version situation: http://cppreference.com, dated 2024.06.10, and the manual page id is std::ranges...s::drop_view(3). Go forth and drop those first N elements, periodt πŸ’…πŸŒˆ

πŸ“¦ where this page comes from