std::ranges::dangling(3)

🌸 std::ranges::dangling(3) 🌸

Okay bestie, this page is from the C++ Standard Libary manual (yes, that's the manual name, typo and all πŸ’…). Buckle up, because this one is a tiny little type with a big "do not dereference me" vibe.


✨ NAME ✨

std::ranges::dangling β€” std::ranges::dangling

πŸ¦‹ Synopsis πŸ¦‹

Defined in header <ranges>.

struct dangling;            (since C++20)

dangling is a placeholder type and an empty class type, used together with the template aliases ranges::borrowed_iterator_t and ranges::borrowed_subrange_t.

When some constrained algorithms that usually return an iterator or a subrange of a range take a particular rvalue range argument that does not model borrowed_range, dangling will be returned instead to avoid returning potentially dangling results. πŸ’€

πŸ’… Member functions πŸ’…

std::ranges::dangling::dangling

constexpr dangling() noexcept = default;   (1)
template<class... Args>                    (2)
constexpr dangling(Args&&...) noexcept { }
  1. dangling is trivially default constructible. πŸŽ€
  2. dangling can be constructed from arguments of arbitrary number and arbitrary non-void type. The construction does not have any side-effect itself. ✨

In other words, after replacing the type (e.g. an iterator type) in a well-formed non-aggregate initialization with dangling, the resulting initialization is also well-formed. No cap.

πŸŽ€ Example πŸŽ€

// Run this code

#include <algorithm>
#include <array>
#include <iostream>
#include <ranges>
#include <type_traits>
#include <string_view>

int main()
{
    auto get_array_by_value = [] { return std::array{0, 1, 0, 1}; };
    auto dangling_iter = std::ranges::max_element(get_array_by_value());
    static_assert(std::is_same_v<std::ranges::dangling, decltype(dangling_iter)>);
//  std::cout << *dangling_iter << '\n'; // compilation error: no match for 'operator*'
// (operand type is 'std::ranges::dangling')

    auto get_persistent_array = []() -> const std::array<int, 4>& {
        static constexpr std::array a{0, 1, 0, 1};
        return a;
    };
    auto valid_iter = std::ranges::max_element(get_persistent_array());
    static_assert(!std::is_same_v<std::ranges::dangling, decltype(valid_iter)>);
    std::cout << *valid_iter << ' '; // 1

    auto get_string_view = [] { return std::string_view{"alpha"}; };
    auto valid_iter2 = std::ranges::min_element(get_string_view());
        // OK: std::basic_string_view models borrowed_range
    static_assert(!std::is_same_v<std::ranges::dangling, decltype(valid_iter2)>);
    std::cout << '\'' << *valid_iter2 << '\'' << '\n'; // 'a'
}
If you dereference a dangling, that's a compilation error, bestie β€” the example literally shows no match for 'operator*'. πŸ’€

🌈 Output 🌈

1 'a'

πŸ‘‘ See also πŸ‘‘

  • ranges::borrowed_iterator_t (C++20) (alias template) β€” obtains iterator type or subrange type of a borrowed_range
  • ranges::borrowed_subrange_t (C++20) (alias template) β€” the other borrowed-range alias template right alongside borrowed_iterator_t
  • ranges::borrowed_range (C++20) (concept) β€” specifies that a type is a range and iterators obtained from an expression of it can be safely returned without danger of dangling

That's the whole page, bestie. Signed off from std::ranges::dangling(3) with source/version http://cppreference.com and date 2024.06.10. Go forth and never dereference a dangling β€” it's giving compilation error realness. πŸ’–βœ¨πŸ«Ά

πŸ“¦ where this page comes from