# std::ranges::find, std::ranges::find_if, std::ranges::find_if_not

< cpp‎ | algorithm‎ | ranges

定义于头文件 `<algorithm>` |  |
调用签名 |  |
template< std::input_iterator I, std::sentinel_for<I> S, class T, class Proj = std::identity > requires std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>, const T*> constexpr I find( I first, S last, const T& value, Proj proj = {} ); | (1) | (C++20 起)
template< ranges::input_range R, class T, class Proj = std::identity > requires std::indirect_binary_predicate<ranges::equal_to, std::projected<ranges::iterator_t<R>, Proj>, const T*> constexpr ranges::borrowed_iterator_t<R> find( R&& r, const T& value, Proj proj = {} ); | (2) | (C++20 起)
template< std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity, std::indirect_unary_predicate<std::projected<I, Proj>> Pred > constexpr I find_if( I first, S last, Pred pred, Proj proj = {} ); | (3) | (C++20 起)
template< ranges::input_range R, class Proj = std::identity, std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred > constexpr ranges::borrowed_iterator_t<R> find_if( R&& r, Pred pred, Proj proj = {} ); | (4) | (C++20 起)
template< std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity, std::indirect_unary_predicate<std::projected<I, Proj>> Pred > constexpr I find_if_not( I first, S last, Pred pred, Proj proj = {} ); | (5) | (C++20 起)
template< ranges::input_range R, class Proj = std::identity, std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred > constexpr ranges::borrowed_iterator_t<R> find_if_not( R&& r, Pred pred, Proj proj = {} ); | (6) | (C++20 起)

返回范围 `[first, last)` 中首个满足特定判别标准的元素：

1) `find` 搜索等于 `value` 的元素。
3) `find_if` 搜索谓词 `pred` 对其返回 true 的元素。
5) `find_if_not` 搜索谓词 `pred` 对其返回 false 的元素。
2,4,6) 同 (1,3,5) ，但以 `r` 为范围，如同以 ranges::begin(r) 为 `first` 并以 ranges::end(r) 为 `last` 。

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

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

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

### 参数

first, last | - | 要检验的范围
r | - | 要检验的范围
value | - | 要与元素比较的值
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

### 返回值

指向满足条件的首个元素的迭代器，或若找不到这种元素则为等于 `last` 的迭代器。

### 复杂度

至多应用 `last` - `first` 次谓词与投影。

### 可能的实现

版本一
    struct find_fn {
      template< std::input_iterator I, std::sentinel_for<I> S,
                class T, class Proj = std::identity >
      requires std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>,
                                              const T*>
      constexpr I operator()( I first, S last, const T& value, Proj proj = {} ) const
      {
          for (; first != last; ++first) {
              if (std::invoke(proj, *first) == value) {
                  return first;
              }
          }
          return first;
      }

      template< ranges::input_range R, class T, class Proj = std::identity >
      requires std::indirect_binary_predicate<ranges::equal_to,
                                              std::projected<ranges::iterator_t<R>, Proj>,
                                              const T*>
      constexpr ranges::borrowed_iterator_t<R>
        operator()( R&& r, const T& value, Proj proj = {} ) const
      {
         return (*this)(ranges::begin(r), ranges::end(r), value, std::ref(proj));
      }
    };

    inline constexpr find_fn find;
版本二
    struct find_if_fn {
      template< std::input_iterator I, std::sentinel_for<I> S,
                class Proj = std::identity,
                std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
      constexpr I operator()( I first, S last, Pred pred = {}, Proj proj = {} ) const
      {
          for (; first != last; ++first) {
              if (std::invoke(pred, std::invoke(proj, *first))) {
                  return first;
              }
          }
          return first;
      }

      template< ranges::input_range R, class Proj = std::identity,
                std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
      constexpr ranges::borrowed_iterator_t<R>
        operator()( R&& r, Pred pred = {}, Proj proj = {} ) const
      {
        return (*this)(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
      }
    };

    inline constexpr find_if_fn find_if;
版本三
    struct find_if_not_fn {
      template< std::input_iterator I, std::sentinel_for<I> S,
                class Proj = std::identity,
                std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
      constexpr I operator()( I first, S last, Pred pred = {}, Proj proj = {} ) const
      {
          for (; first != last; ++first) {
              if (!std::invoke(pred, std::invoke(proj, *first))) {
                  return first;
              }
          }
          return first;
      }

      template< ranges::input_range R, class Proj = std::identity,
                std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
      constexpr ranges::borrowed_iterator_t<R>
        operator()( R&& r, Pred pred = {}, Proj proj = {} ) const
      {
        return (*this)(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
      }
    };

    inline constexpr find_if_not_fn find_if_not;

### 示例

以下示例在 int 的 vector 中寻找 int 。

    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <iterator>

    int main()
    {
        int n1 = 3;
        int n2 = 5;

        std::vector<int> v{4, 1, 3, 2};

        namespace ranges = std::ranges;

        auto result1 = ranges::find(v, n1);
        auto result2 = ranges::find(v.begin(), v.end(), n2);

        if (result1 != v.end()) {
            std::cout << "v contains: " << n1 << '\n';
        } else {
            std::cout << "v does not contain: " << n1 << '\n';
        }

        if (result2 != v.end()) {
            std::cout << "v contains: " << n2 << '\n';
        } else {
            std::cout << "v does not contain: " << n2 << '\n';
        }

        auto is_even = [](int x) { return x % 2 == 0; };
        auto divides_13 = [](int x) { return x % 13 == 0; };

        auto result3 = ranges::find_if(v.begin(), v.end(), is_even);
        auto result4 = ranges::find_if(v, divides_13);
        if (result3 != v.end()) {
          std::cout << "First even element in v: " << *result3 << '\n';
        } else {
          std::cout << "No even elements in v\n";
        }

        if (result4 != v.end()) {
          std::cout << "First element divisible by 13 in v: " << *result4 << '\n';
        } else {
          std::cout << "No elements in v are divisible by 13\n";
        }

        auto result5 = ranges::find_if_not(v.begin(), v.end(), divides_13);
        auto result6 = ranges::find_if_not(v, is_even);
        if (result5 != v.end()) {
          std::cout << "First element indivisible by 13 in v: " << *result5 << '\n';
        } else {
          std::cout << "No elements in v are divisible by 13\n";
        }

        if (result6 != v.end()) {
          std::cout << "First odd element in v: " << *result6 << '\n';
        } else {
          std::cout << "No even elements in v\n";
        }
    }

输出：

    v contains: 3
    v does not contain: 5
    First even element in v: 4
    No elements in v are divisible by 13
    First element indivisible by 13 in v: 4
    First odd element in v: 1

### 参阅

ranges::adjacent_find (C++20) | 查找首对相邻的相同（或满足给定谓词的）元素 (niebloid)
ranges::find_end (C++20) | 在特定范围中寻找最后出现的元素序列 (niebloid)
ranges::find_first_of (C++20) | 搜索元素集合中的任一元素 (niebloid)
ranges::mismatch (C++20) | 寻找两个范围出现不同的首个位置 (niebloid)
ranges::search (C++20) | 搜索一个元素范围 (niebloid)
find find_if find_if_not (C++11) | 寻找首个满足特定判别标准的元素 (函数模板)