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

来自cppreference.com
< cpp‎ | algorithm‎ | ranges
 
 
算法库
受约束算法及范围上的算法 (C++20)
包含算法例如 ranges::copy, ranges::sort, ...
执行策略 (C++17)
排序和相关操作
划分操作
排序操作
二分搜索操作(在已划分范围上)
集合操作(在有序范围上)
归并操作(在有序范围上)
堆操作
最小/最大操作
(C++11)
(C++17)
字典序比较操作
排列操作
C 库

数值运算
(C++11)                       
在未初始化内存上的操作
 
受约束算法
本菜单中的所有名字均属于命名空间 std::ranges
不修改序列的操作
修改序列的操作
划分操作
排序操作
二分搜索操作(在有序范围上)
       
       
集合操作(在有序范围上)
堆操作
最小/最大操作
       
       
排列操作
折叠操作
数值操作
(C++23)            
未初始化存储上的操作
返回类型
 
在标头 <algorithm> 定义
调用签名
(1)
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 = {} );
(C++20 起)
(C++26 前)
template< std::input_iterator I, std::sentinel_for<I> S,

          class Proj = std::identity,
          class T = std::projected_value_t<I, Proj> >
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 = {} );
(C++26 起)
(2)
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 = {} );
(C++20 起)
(C++26 前)
template< ranges::input_range R, class Proj = std::identity,

          class T = std::projected_value_t<ranges::iterator_t<R>, Proj> >
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 = {} );
(C++26 起)
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 起)

返回范围 [firstlast) 中首个满足特定判别标准的元素:

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 次谓词与投影。

可能的实现

find
struct find_fn
{
    template<std::input_iterator I, std::sentinel_for<I> S,
             class Proj = std::identity,
             class T = std::projected_value_t<I, Proj>>
    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;
find_if
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;
find_if_not
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;

注解

功能特性测试 标准 功能特性
__cpp_lib_algorithm_default_value_type 202403 (C++26) 算法中的列表初始化 (1,2)

示例

#include <algorithm>
#include <cassert>
#include <complex>
#include <format>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
 
void projector_example()
{
    struct folk_info
    {
        unsigned uid;
        std::string name, position;
    };
 
    std::vector<folk_info> folks
    {
        {0, "Ana", "dev"},
        {1, "Bob", "devops"},
        {2, "Eve", "ops"}
    };
 
    const auto who{"Eve"};
 
    if (auto it = std::ranges::find(folks, who, &folk_info::name); it != folks.end())
        std::cout << std::format("人物简介:\n"
                                 "    UID:{}\n"
                                 "    名字:{}\n"
                                 "    职位:{}\n\n",
                                 it->uid, it->name, it->position);
}
 
int main()
{
    namespace ranges = std::ranges;
 
    projector_example();
 
    const int n1 = 3;
    const int n2 = 5;
    const auto v = {4, 1, 3, 2};
 
    if (ranges::find(v, n1) != v.end())
        std::cout << "v 包含:" << n1 << '\n';
    else
        std::cout << "v 不包含:" << n1 << '\n';
 
    if (ranges::find(v.begin(), v.end(), n2) != v.end())
        std::cout << "v 包含:" << n2 << '\n';
    else
        std::cout << "v 不包含:" << n2 << '\n';
 
    auto is_even = [](int x) { return x % 2 == 0; };
 
    if (auto result = ranges::find_if(v.begin(), v.end(), is_even); result != v.end())
        std::cout << "v 中的第一个偶数元素:" << *result << '\n';
    else
        std::cout << "v\ 中没有偶数元素n";
 
    if (auto result = ranges::find_if_not(v, is_even); result != v.end())
        std::cout << "v 中的第一个奇数元素:" << *result << '\n';
    else
        std::cout << "v 中没有奇数元素\n";
 
    auto divides_13 = [](int x) { return x % 13 == 0; };
 
    if (auto result = ranges::find_if(v, divides_13); result != v.end())
        std::cout << "v 中的第一个可被 13 整除的元素:" << *result << '\n';
    else
        std::cout << "v 中没有可被 13 整除的元素\n";
 
    if (auto result = ranges::find_if_not(v.begin(), v.end(), divides_13);
        result != v.end())
        std::cout << "v 中的第一个不可被 13 整除的元素:" << *result << '\n';
    else
        std::cout << "v 中没有不可被 13 整除的元素\n";
 
    std::vector<std::complex<double>> nums{{4, 2}};
    #ifdef __cpp_lib_algorithm_default_value_type
        // (2) 中推导的 T 使得列表初始化成为可能
        const auto it = ranges::find(nums, {4, 2});
    #else
        const auto it = ranges::find(nums, std::complex<double>{4, 2});
    #endif
    assert(it == nums.begin());
}

输出:

人物简介:
    UID:2
    名字:Eve
    职位:ops
 
v 包含:3
v 不包含:5
v 中的第一个偶数元素:4
v 中的第一个奇数元素:1
v 中没有可被 13 整除的元素
v 中的第一个不可被 13 整除的元素:4

参阅

查找首对相邻的相同(或满足给定谓词的)元素
(niebloid)
查找特定范围中最后出现的元素序列
(niebloid)
查找范围中的任一元素
(niebloid)
寻找两个范围出现不同的首个位置
(niebloid)
搜索一个元素范围的首次出现
(niebloid)
寻找首个满足特定判别标准的元素
(函数模板)