std::ranges::cend(3)

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

✨ NAME ✨

std::ranges::cend β€” okay bestie, this is literally the "const end" bestie πŸ’…, the one that gives you the end sentinel for a const range, periodt. It lives in the C++ Standard Library (C++20 energy, iykyk).

🌸 SYNOPSIS 🌸

So here's the tea πŸ«– β€” this icon is defined in two headers, <ranges> and <iterator>, and it's an inline namespace situation:

inline namespace /* unspecified */ {
    inline constexpr /* unspecified */ cend = /* unspecified */;  // (since C++20)
}

It's a customization point object, which is giving fancy const function object realness. 😌

πŸ’… Call signature πŸ’…

template< class T >
    requires /* see below */
constexpr /* see below */ auto cend( T&& t );  // (since C++20)

It returns a sentinel for the constant iterator (since C++23) β€” which is like, the "end" marker for a const-qualified (until C++23) range. No cap, fr fr. πŸŽ€

The original page has a lil diagram called range-begin-end.svg right here β€” just imagine the range-begin-end vibes, bestie. πŸ¦‹

🧚 The whole CT situation 🧚

Let CT be:

  • const std::remove_reference_t<T>& if the argument is an lvalue (i.e. T is an lvalue reference type), (until C++23)
  • const T otherwise.

A call to ranges::cend is expression-equivalent to ranges::end(static_cast<CT&&>(t)). Slay. ✨

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

  • std::const_sentinel<decltype(U)>(U) for some expression U equivalent to ranges::end(/*possibly-const-range*/(t)). (since C++23)

In all other cases, a call to ranges::cend is ill-formed, which can result in substitution failure when the call appears in the immediate context of a template instantiation. So like, be careful bestie β€” that's a no-go zone. πŸ˜­πŸ’€

If ranges::cend(e) is valid for an expression e, where decltype((e)) is T, then CT models std::ranges::range, and (until C++23) std::sentinel_for<S, I> is true in all cases, where S is decltype(ranges::cend(e)), and I is decltype(ranges::cbegin(e)). Additionally, S models constant-iterator if it models input_iterator. (since C++23) Obsessed with the details, honestly. πŸ‘‘

πŸŽ€ CUSTOMIZATION POINT OBJECTS πŸŽ€

The name ranges::cend denotes a customization point object, which is a const function object of a literal semiregular class type. For exposition purposes, the cv-unqualified version of its type is denoted as __cend_fn. Cute, right? That's the internal bestie name. πŸ’–

All instances of __cend_fn are equal. The effects of invoking different instances of type __cend_fn on the same arguments are equivalent, regardless of whether the expression denoting the instance is an lvalue or rvalue, and is const-qualified or not (however, a volatile-qualified instance is not required to be invocable). So basically, ranges::cend can be copied freely and its copies can be used interchangeably. It's giving "copy me, I'm flexible" energy. 🌈

Given a set of types Args..., if std::declval<Args>()... meet the requirements for arguments to ranges::cend above, __cend_fn models:

  • std::invocable<__cend_fn, Args...>,
  • std::invocable<const __cend_fn, Args...>,
  • std::invocable<__cend_fn&, Args...>, and
  • std::invocable<const __cend_fn&, Args...>.

Otherwise, no function call operator of __cend_fn participates in overload resolution. That's the vibe check β€” if it doesn't fit, it doesn't sit. 🫢

πŸ“ EXAMPLE πŸ“

Run this code, bestie:

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

int main()
{
    std::vector vec{3, 1, 4};
    int arr[]{5, 10, 15};

    assert(std::ranges::find(vec, 5) == std::ranges::cend(vec));
    assert(std::ranges::find(arr, 5) != std::ranges::cend(arr));
}

It's literally asserting that finding 5 in vec lands exactly at ranges::cend(vec) (because 5 is not in there, so it's the end), but for arr, 5 is the first element, so it's not the end. Iconic. πŸ”₯

πŸ¦‹ SEE ALSO πŸ¦‹

  • ranges::end β€” returns a sentinel indicating the end of a range (C++20) (customization point object)
  • end β€” returns an iterator to the end of a container or array (C++11) (function template)
  • cend β€” returns an iterator to the end of a container or array (C++14) (function template)

This page was brought to you by http://cppreference.com, version 2024.06.10, and it's literally page std::ranges::cend(3). Bye bestie! πŸ’…βœ¨πŸ«ΆπŸŽ€πŸŒΈ

πŸ“¦ where this page comes from