# std::ranges::borrowed_range, std::ranges::enable_borrowed_range

< cpp‎ | ranges

定义于头文件 `<ranges>` |  |
template<class R> concept borrowed_range = ranges::range<R> && (std::is_lvalue_reference_v<R> || ranges::enable_borrowed_range<std::remove_cvref_t<R>>); | (1) | (C++20 起)
template<class R> inline constexpr bool enable_borrowed_range = false; | (2) | (C++20 起)

1) 概念 `borrowed_range` 定义范围的要求，使得函数能按值接收它，并返回从它获得的迭代器，而无悬垂之虞。
2) `enable_borrowed_range` 变量模板用于指示一个 `range` 是否为 `borrowed_range` 。主模板定义为 false 。

### 语义要求

若 `T` 为右值引用类型则令 `U` 为 std::remove_reference_t<T> ，否则为 `T` 。给定 `U` 类型变量 `u` ， `T` 实现 `borrowed_range` 仅若从 `u` 获得的迭代器的合法性不绑定到该变量的生存期。

### 特化

`enable_borrowed_range` 对下列标准模板的所有特化定义为 true ：

- `std::basic_string_view`
- `std::span`
- `std::ranges::subrange`
- `std::ranges::ref_view`
- `std::ranges::empty_view`
- `std::ranges::iota_view`

`enable_borrowed_range` 对下列标准范围适配器定义为 true 当且仅当 std::ranges::enable_borrowed_range<V> 为 true ，其中 `V` 是底层视图类型：

- `std::ranges::owning_view`
- `std::ranges::take_view`
- `std::ranges::drop_view`
- `std::ranges::drop_while_view`
- `std::ranges::common_view`
- `std::ranges::reverse_view`
- `std::ranges::elements_view`

`std::ranges::adjacent_view` | (C++23 起)

对 `std::ranges::zip_view` 的特化定义为 true 当且仅当 (std::ranges::enable_borrowed_range<Vs> && ...) 为 true ，其中 `Vs...` 为其所适配的所有视图类型。 | (C++23 起)

用户可对要实现 `borrowed_range` 的无 cv 限定的程序定义类型特化 `enable_borrowed_range` 为 true ，而对不实现的类型特化为 false 。这些特化应当可用于常量表达式并拥有 const bool 类型。

### 示例

演示 `enable_borrowed_range` 对程序定义类型的特化。这种特化防御潜在悬垂的结果。

    #include <algorithm>
    #include <array>
    #include <cstddef>
    #include <iostream>
    #include <ranges>
    #include <span>
    #include <type_traits>

    template <typename T, std::size_t N>
    struct MyRange : std::array<T, N> { };

    template <typename T, std::size_t N>
    inline constexpr bool std::ranges::enable_borrowed_range<MyRange<T, N>> = false;

    template <typename T, std::size_t N>
    struct MyBorrowedRange : std::span<T, N> { };

    template <typename T, std::size_t N>
    inline constexpr bool std::ranges::enable_borrowed_range<MyBorrowedRange<T, N>> = true;

    int main()
    {
        static_assert(std::ranges::range<MyRange<int, 8>>);
        static_assert(std::ranges::borrowed_range<MyRange<int, 8>> == false);
        static_assert(std::ranges::range<MyBorrowedRange<int, 8>>);
        static_assert(std::ranges::borrowed_range<MyBorrowedRange<int, 8>> == true);

        auto getMyRangeByValue = [] { return MyRange<int, 4>{ {1, 2, 42, 3} }; };
        auto dangling_iter = std::ranges::max_element(getMyRangeByValue());
        static_assert(std::is_same_v<std::ranges::dangling, decltype(dangling_iter)>);
    //  *dangling_iter; // 编译错误（即悬垂保护生效。）

        auto my = MyRange<int, 4>{ {1, 2, 42, 3} };
        auto valid_iter = std::ranges::max_element(my);
        std::cout << *valid_iter << ' '; // OK: 42

        auto getMyBorrowedRangeByValue = [] {
            static int sa[4] {1, 2, 42, 3};
            return MyBorrowedRange<int, std::size(sa)>{sa};
        };
        auto valid_iter2 = std::ranges::max_element(getMyBorrowedRangeByValue());
        std::cout << *valid_iter2 << '\n'; // OK ： 42
    }

输出：

    42 42