# std::ranges::find_first_of

< cpp‎ | algorithm‎ | ranges

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

1) 在范围 `[first1, last1)` 中搜索任何范围 `[first2, last2)` 中的元素，分别以 `proj1` 与 `proj2` 投影范围。用二元谓词 `pred` 比较投影后的元素。
2) 同 (1) ，但以 `r1` 为第一源范围并以 `r2` 为第二源范围，如同以 ranges::begin(r1) 为 `first1` ，以 ranges::end(r1) 为 `last1` ，以 ranges::begin(r2) 为 `first2` ，并以 ranges::end(r2) 为 `last2` 。

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

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

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

### 参数

first1, last1 | - | 要检验的元素范围（又称草堆）
first2, last2 | - | 要搜索的元素范围（又称针）
r1 | - | 要检验的元素范围（又称草堆）
r2 | - | 要搜索的元素范围（又称针）
pred | - | 比较元素的二元谓词
proj1 | - | 应用到第一范围中元素的投影
proj2 | - | 应用到第二范围中元素的投影

### 返回值

指向范围 `[first1, last1)` 中首个在投影后等于来自范围 `[first2, last2)` 中元素的迭代器。若找不到这种元素，则返回等于 `last1` 的迭代器。

### 复杂度

至多应用 `(S*N)` 次比较和各自的投影，其中
(1) S = ranges::distance(first2, last2) 而 N = ranges::distance(first1, last1) ；
(2) S = ranges::size(r2) 而 N = ranges::size(r1) 。

### 可能的实现

    struct find_first_of_fn {

      template<std::input_iterator I1, std::sentinel_for<I1> S1,
               std::forward_iterator I2, std::sentinel_for<I2> S2,
               class Pred = ranges::equal_to,
               class Proj1 = std::identity,
               class Proj2 = std::identity>
      requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr I1 operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                              Proj1 proj1 = {}, Proj2 proj2 = {}) const {
        for (; first1 != last1; ++first1)
          for (auto i = first2; i != last2; ++i)
            if (std::invoke(pred, std::invoke(proj1, *first1), std::invoke(proj2, *i)))
              return first1;
        return first1;
      }

      template<ranges::input_range R1, ranges::forward_range R2,
               class Pred = ranges::equal_to,
               class Proj1 = std::identity,
               class Proj2 = std::identity>
        requires std::indirectly_comparable<ranges::iterator_t<R1>,
                                            ranges::iterator_t<R2>,
                                            Pred, Proj1, Proj2>
        constexpr ranges::borrowed_iterator_t<R1>
          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 find_first_of_fn find_first_of{};

### 示例

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

    int main()
    {
        namespace rng = std::ranges;

        constexpr static auto haystack = {1, 2, 3, 4};
        constexpr static auto needles  = {0, 3, 4, 3};

        constexpr auto found1 = rng::find_first_of(haystack.begin(), haystack.end(),
                                                   needles.begin(), needles.end());
        static_assert(std::distance(haystack.begin(), found1) == 2);

        constexpr auto found2 = rng::find_first_of(haystack, needles);
        static_assert(std::distance(haystack.begin(), found2) == 2);

        constexpr static auto negatives = {-6, -3, -4, -3};
        constexpr auto not_found = rng::find_first_of(haystack, negatives);
        static_assert(not_found == haystack.end());

        constexpr auto found3 = rng::find_first_of(haystack, negatives,
            [](int x, int y) { return x == -y; }); // 使用二元比较器
        static_assert(std::distance(haystack.begin(), found3) == 2);

        struct P { int x, y; };
        constexpr static auto p1 = { P{1, -1}, P{2, -2}, P{3, -3}, P{4, -4} };
        constexpr static auto p2 = { P{5, -5}, P{6, -3}, P{7, -5}, P{8, -3} };

        // 仅比较 P::y 数据成员，通过投影它们：
        const auto found4 = rng::find_first_of(p1, p2, {}, &P::y, &P::y);
        std::cout << "First equivalent element {" << found4->x << ", " << found4->y
                  << "} was found at position " << std::distance(p1.begin(), found4)
                  << ".\n";
    }

输出：

    First equavalent element {3, -3} was found at position 2.

### 参阅

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