# std::ranges::ends_with

< cpp‎ | algorithm‎ | ranges

定义于头文件 `<algorithm>` |  |
调用签名 |  |
template<std::input_iterator I1, std::sentinel_for<I1> S1, std::input_iterator I2, std::sentinel_for<I2> S2, class Pred = ranges::equal_to, class Proj1 = std::identity, class Proj2 = std::identity> requires (std::forward_iterator<I1> || std::sized_sentinel_for<S1, I1>) && (std::forward_iterator<I2> || std::sized_sentinel_for<S2, I2>) && std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2> constexpr bool ends_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); | (1) | (C++23 起)
template<ranges::input_range R1, ranges::input_range R2, class Pred = ranges::equal_to, class Proj1 = std::identity, class Proj2 = std::identity> requires (ranges::forward_range<R1> || ranges::sized_range<R1>) && (ranges::forward_range<R2> || ranges::sized_range<R2>) && std::indirectly_comparable<ranges::iterator_t<R1>, ranges::iterator_t<R2>, Pred, Proj1, Proj2> constexpr bool ends_with(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); | (2) | (C++23 起)

检查第二范围是否匹配第一范围的后缀。

1) 令 `N1` 与 `N2` 分别为 ranges::distance(first1, last1) 与 ranges::distance(first2, last2) 。若 N1 < N2 则返回 false 。否则，当且仅当 `[first2, last2)` 范围中的每个元素均等于 `[first1 + N1 - N2, last1)` 中的对应元素才返回 true 。通过应用二元谓词 `pred` 到分别由 `proj1` 与 `proj2` 投影的两个范围中的元素进行比较。
2) 同， (1) ，但以 `r1` 与 `r2` 为源范围，如同以 ranges::begin(r1) 为 `first1` ，以 ranges:begin(r2) 为 `first2` ，以 ranges::end(r1) 为 `last1` ，并以 ranges::end(r2) 为 `last2` 。

此页面上描述的仿函数实体是 niebloid ，即：

- 调用它们中的任何一者时不可指定显式模板实参。
- 它们无一对实参依赖查找可见。
- 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

### 参数

first1, last1 | - | 要检验的元素范围
r1 | - | 要检验的元素范围
first2, last2 | - | 要用作后缀的元素范围
r2 | - | 要用作后缀的元素范围
pred | - | 比较投影后元素的二元谓词
proj1 | - | 应用到要检验的元素范围的投影
proj2 | - | 应用到要用作后缀的元素范围的投影

### 返回值

若第二范围匹配第一范围的后缀则为 true ，否则为 false 。

### 复杂度

线性：至多应用 `min(N1, N2)` 次谓词和两个投影。若 N1 < N2 则不应用谓词和两个投影。

若 `N1` 与 `N2` 均能以常数时间计算（即两个迭代器-哨位类型对均实现 `sized_sentinel_for` ，或两个范围类型均实现 `sized_range` ）且 N1 < N2 ，则时间复杂度为常数。

### 可能的实现

    struct ends_with_fn {
      template<std::input_iterator I1, std::sentinel_for<I1> S1,
               std::input_iterator I2, std::sentinel_for<I2> S2,
               class Pred = ranges::equal_to,
               class Proj1 = std::identity, class Proj2 = std::identity>
        requires (std::forward_iterator<I1> || std::sized_sentinel_for<S1, I1>) &&
                 (std::forward_iterator<I2> || std::sized_sentinel_for<S2, I2>) &&
                 std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                                Proj1 proj1 = {}, Proj2 proj2 = {}) const {
        const auto n1 = ranges::distance(first1, last1);
        const auto n2 = ranges::distance(first2, last2);

        if (n1 < n2)
          return false;
        ranges::advance(first1, n1 - n2);
        return ranges::equal(std::move(first1), std::move(last1),
                             std::move(first2), std::move(last2),
                             std::move(pred), std::move(proj1), std::move(proj2));
      }

      template<ranges::input_range R1, ranges::input_range R2,
               class Pred = ranges::equal_to,
               class Proj1 = std::identity, class Proj2 = std::identity>
        requires (ranges::forward_range<R1> || ranges::sized_range<R1>) &&
                 (ranges::forward_range<R2> || ranges::sized_range<R2>) &&
                 std::indirectly_comparable<ranges::iterator_t<R1>,
                                            ranges::iterator_t<R2>,
                                            Pred, Proj1, Proj2>
      constexpr bool operator()(R1&& r1, R2&& r2, Pred pred = {},
                                Proj1 proj1 = {}, Proj2 proj2 = {}) const {
        return (*this)(ranges::begin(r1), ranges::end(r1),
                       ranges::begin(r2), ranges::end(r2),
                       std::move(pred), std::move(proj1), std::move(proj2));
      }
    };

    inline constexpr ends_with_fn ends_with{};

### 示例

    #include <array>
    #include <algorithm>
    #include <iostream>

    int main()
    {
        std::cout
            << std::boolalpha
            << std::ranges::ends_with("static_cast", "cast") << '\n'
            << std::ranges::ends_with("const_cast", "cast") << '\n'
            << std::ranges::ends_with("reinterpret_cast", "cast") << '\n'
            << std::ranges::ends_with("dynamic_cast", "cast") << '\n'
            << std::ranges::ends_with("move", "cast") << '\n'
            << std::ranges::ends_with("move_if_noexcept", "cast") << '\n'
            << std::ranges::ends_with("forward", "cast") << '\n'
            << std::ranges::ends_with("as_const", "cast") << '\n'
            << std::ranges::ends_with("bit_cast", "cast") << '\n'
            << std::ranges::ends_with("to_underlying", "cast") << '\n';
            << std::ranges::ends_with(std::array{1,2,3,4}, std::array{3,4}) << '\n'
            << std::ranges::ends_with(std::array{1,2,3,4}, std::array{4,5}) << '\n';
    }

输出：

    true
    true
    true
    true
    false
    false
    false
    false
    true
    false

### 参阅

ranges::starts_with (C++23) | 检查一个范围是否始于另一范围 (niebloid)
ends_with (C++20) | 检查 string 是否终于给定后缀 (`std::basic_string<CharT,Traits,Allocator>` 的公开成员函数)
ends_with (C++20) | 检查 string_view 是否终于给定后缀 (`std::basic_string_view<CharT,Traits>` 的公开成员函数)