std::unreac...ble_sentinel(3)

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

πŸ’… NAME πŸ’…

okay so bestie, this is the std::unreachable_sentinel_t / std::unreachable_sentinel page from the C++ Standard Libary manual β€” yes, the header is out here truncating the title like std::unreac...ble_sentinel(3), and the NAME line is literally std::unreachable_sentinel_t,std::unreachable_sentinel. We’re folding that manual-name moment in right here instead of copy-pasting the header line, periodt. πŸ’–


✨ Synopsis ✨

Defined in header <iterator>

struct unreachable_sentinel_t;                                  (1)

(since C++20)

inline constexpr unreachable_sentinel_t unreachable_sentinel{}; (2)

(since C++20)

  1. unreachable_sentinel_t is an empty class type that can be used to denote the β€œupper bound” of an unbounded interval. πŸ¦‹
  2. unreachable_sentinel is a constant of type unreachable_sentinel_t.

🌈 Non-member functions 🌈

  • operator== β€” compares an unreachable_sentinel_t with a value of any (C++20) weakly_incrementable type; (function template). πŸ”₯

πŸ¦‹ operator==(std::unreachable_sentinel_t) πŸ¦‹

Here’s the signature vibe:

template<std::weakly_incrementable I>
friend constexpr bool operator==( unreachable_sentinel_t, const I& )
noexcept
{ return false; }

It’s (since C++20), and it’s literally noexcept too. πŸ’…

unreachable_sentinel_t can be compared with any weakly_incrementable type and the result is always false β€” yes, always, no cap. It’s giving β€œI am the sentinel that is never reached” energy. 😭

Also important: this function template is not visible to ordinary unqualified or qualified lookup, and can only be found by argument-dependent lookup when std::unreachable_sentinel_t is an associated class of the arguments. That’s the iykyk ADL lore. 🧚


πŸ”₯ Example πŸ”₯

This is the whole β€œRun this code” moment, verbatim bestie:

// Run this code

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <iterator>

template<class CharT>
constexpr std::size_t strlen(const CharT *s)
{
    return std::ranges::find(s, std::unreachable_sentinel, CharT{}) - s;
}

template<class CharT>
constexpr std::size_t pos(const CharT *haystack, const CharT *needle)
{
    // search(begin, unreachable_sentinel) is usually more efficient than
    // search(begin, end) due to one less comparison per cycle.
    // But "needle" MUST BE in the "haystack", otherwise the call is UB,
    // which is a compile-time error in constexpr context.
    return std::ranges::search(
               haystack, std::unreachable_sentinel,
               needle, needle + strlen(needle)
           ).begin() - haystack;
}

int main()
{
    static_assert(strlen("The quick brown fox jumps over the lazy dog.") == 44);
    static_assert(pos("const short int", "short") == 6);
//  static_assert(pos("long int", "float")); // compile-time error
}

the commented-out // static_assert(pos("long int", "float")); // compile-time error is there to remind you that the "needle" MUST BE in the "haystack" β€” otherwise the call is UB, and in a constexpr context that UB shows up as a compile-time error. Not me being dramatic, that’s literally the comment. πŸ’€


πŸ’œ See also πŸ’œ

The See also lineup is ranges::iota_view and views::iota: ranges::iota_view is (C++20) (class template), views::iota is (C++20) (customization point object), and the description that shows up is β€œa view consisting of a sequence generated by repeatedly incrementing an initial value.” 🌸

source/version + date: http://cppreference.com, 2024.06.10 β€” mwah, that’s the footer sign-off, bestie πŸ’‹

πŸ“¦ where this page comes from