C++ find find_if lambda表达式 理解和用法

find 和 find_if 都是stl 标准算法,标准库都已经提供了标准的算法了,那就直接用吧。令外说一下,如果要使用find find_if 等一系列函数需要包含 #include <algorithm> 头文件才可以。用到find_if 需要用到lambda表达式,正好一起记录了。

第一部分:代码展示。
第二部分:分析代码

1. 代码展示

#include "stdafx.h"
#include <algorithm>
#include <iostream>
#include <string>
#include <list>
using namespace std;
class Demo
{
public:
	Demo(int age, string name)
	{
		this->age = age;
		this->name = name;
	}
	bool operator==(const Demo &another) const
	{
		std::cout << "进入Demo == 函数,比较变量:" << age << std::endl;
		return (age == another.age);
	}
	int age;
	string name;
};
typedef struct finder_t
{
	finder_t(int n) : age(n) { }
	bool operator()(Demo *another)
	{
		std::cout << "进入谓词函数,比较变量:" << another->age << std::endl;
		return (age == another->age);
	}
	int age;
}finder_t;
int main(int argc, char *argv[])
{
	/*1. 查找标准类型的数值,例如int,string*/
	int value = 1;
	list<int> list_1;
	for (int i = 0; i < 10; i++) {
		list_1.push_back(i);
	}
	list<int>::iterator list_it = find(list_1.begin(), list_1.end(), value);
	if (list_it != list_1.end()) {
		std::cout << "找到了value:" << value << std::endl;
	}
	else {
		std::cout << "没有找到找到了value:" << value << std::endl;
	}
	/*2. 如果list里边存放着不是标准类型的数据,比如放着一个类,怎么办?
	*需要重载==操作符,其实也就是自己实现比较的规则。
	* */
	list<Demo>list_2;
	for (int i = 0; i < 10; i++)
	{
		Demo D(i, "cxtan");
		list_2.push_back(D);
	}
	Demo demo = Demo(2, "cxtan");
	list<Demo>::iterator list_it2 = find(list_2.begin(), list_2.end(), demo);
	if (list_it2 != list_2.end())
	{
		std::cout << "找到了age:" << demo.age << std::endl;
	}
	else {
		std::cout << "没有找到找到了age: " << demo.age << std::endl;
	}

	/*3. 另外一种情况就是list里边放着是对象指针,例如list<Demo *>,这时候怎么办,就不能用find了,因为重载==的参数是对象而不是对象指针
	*这时候需要我们使用find_if 方法。查看find_if 的定义:
	*template<class InputIterator, class Predicate>
	InputIterator find_if(InputIterator _First, InputIterator _Last, Predicate _Pred);

	Parameters
	_First
	An input iterator addressing the position of the first element in the range to be searched.
	_Last
    An input iterator addressing the position one past the final element in the range to be searched.
	_Pred
    User-defined predicate function object that defines the condition to be satisfied by the element being searched for. A predicate takes single argument and returns true or false.
	用户定义的谓词函数对象,它定义要被搜索的元素满足的条件。谓词接受单个参数并返回true或false。
	从说明可以看出来,第一个,第二个和find一样,第三个参数需要传递一个谓词来实现我们自己的判断。
	*函数对象(也叫functor),听起来或许有点陌生,但他们是c++实体,即使你没有用过,也一定见过,只是你没有意识到而已。
	从概念上讲,函数对象时用作函数的对象;但是从实现上来说,函数对象时实现了 operate()的类的对象。虽然函数和函数指针也可以归为函数对象,但实现了operate()的类的对象才能保存状态,才能用于STL。
	我们直接看定义:
	- 一元函数:接受一个参数的函数,如f(x)。如果一元函数返回一个BOOL类型的值,则该函数称为谓词。
	- 二元函数:接受2个参数的函数,如f(x,y)。如果二元函数返回一个BOOL值,则该函数称为二元谓词。
	之所以给返回布尔类型的函数对象专门命名,是因为谓词是用来为算法判断服务的。
	*谓词大体就说这些,后期会在写一篇专门介绍函数对象,和谓词的介绍
	* */
	list<Demo *>list_3;
	Demo *D = NULL;
	int age = 3;
	for (int i = 0; i < 10; i++)
	{
		D = new Demo(i, "cxtan");
		list_3.push_back(D);
	}
	list<Demo *>::iterator list_it3 = find_if(list_3.begin(), list_3.end(), finder_t(age));
	if (list_it3 != list_3.end())
	{
		std::cout << "找到了age:" << age << std::endl;
	}
	else
	{
		std::cout << "没有找到找到了age: " << age << std::endl;
	}
	/*
	* 4. find_if可以实现查找函数指针的方法,find_if最后一个参数,是需要谓词的,但是每次定一个结构体去实现operator()去实现谓词函数岂不是很麻烦,所以我们可以使用
	* lambda表达式来搞。
	* lambda 定义:
	* [capture list] (params list) mutable exception-> return type { function body }
	*	capture list:捕获外部变量列表
		params list:形参列表
		mutable指示符:用来说用是否可以修改捕获的变量
		exception:异常设定
		return type:返回类型
		function body:函数体
		常见的格式
		1	[capture list] (params list) -> return type {function body} 声明了返回值,参数的
		2	[capture list] (params list) {function body}省略了返回值类型,但编译器可以根据以下规则推断出Lambda表达式的返回类型: (1):如果function body中存在return语句,则该Lambda表达式的返回类型由return语句的返回类型确定; (2):如果function body中没有return语句,则返回值为void类型。
		3	[capture list] {function body} 格式3中省略了参数列表,类似普通函数中的无参函数。
		具体的lambda表达式的用法,请进入传送门:[lambda详解](https://blog.csdn/lcalqf/article/details/79401210)
		下面开始使用lambda表达式来使用find_if
	*/
	list<Demo *>list_4;
	Demo *D1 = NULL;
	int age4 = 4;
	for (int i = 0; i < 10; i++)
	{
		D1 = new Demo(i, "cxtan");
		list_4.push_back(D1);
	}
	list<Demo *>::iterator list_it4 = find_if(list_4.begin(), list_4.end(), [age4](Demo *another) {
		std::cout << "进入lambda表达式,比较变量:" << another->age << std::endl;
		return (age4 == another->age);
	});
	if (list_it4 != list_4.end())
	{
		std::cout << "找到了age:" << age4 << std::endl;
	}
	else
	{
		std::cout << "没有找到找到了age: " << age4 << std::endl;
	}
	system("pause");
}


好了基本的find和find_if 和lambda表达式 已经讲完了,以后有了新的想法接着更新。

2. 分析代码

我们先看find的定义:
template<class InputIterator, class T>
InputIterator find (InputIterator first, InputIterator last, const T& val)
{
while (first!=last) {
if (*first==val) return first;
++first;
}
return last;
}

  1. find查找一个标准类型的方式:
    find的实现就是通过==操作符来判断是否查找到,为什么对迭代器取引用就是值的本身,这个以后会写一片C++ 迭代器的文章,在这就不做深究了。这是标准类型的时候,如果列表里边用的不是标准类型而是一个类怎么办,就需要用到重载= =操作符了。

  2. find 查找一个不是标准类型的值。
    假如find查找的时候,迭代器里边存的不是标准类型,而是一个类对象,那就需要这个类重载==操作符了,在使用= =运算符的时候使用我们自己的重载函数来作对比。

  3. 加入查找的是一个对象指针怎么办,那就不能用find函数了,find函数接收对象类型,不能接受对象指针类型,那就需要用到了find_if函数。
    看下find_if的实现:

first, last
template<class InputIterator, class UnaryPredicate>
InputIterator find_if (InputIterator first, InputIterator last, UnaryPredicate pred)
{
while (first!=last) {
if (pred(*first)) return first;
++first;
}
return last;
}

find_if 前两个参数和find一样,最后一个参数需要传入一个一元函数(也就是一个参数的函数)
用户定义的谓词函数对象,它定义要被搜索的元素满足的条件。谓词接受单个参数并返回true或false。
从说明可以看出来,第一个,第二个和find一样,第三个参数需要传递一个谓词来实现我们自己的判断。
*函数对象(也叫functor),听起来或许有点陌生,但他们是c++实体,即使你没有用过,也一定见过,只是你没有意识到而已。
从概念上讲,函数对象是用作函数的对象;但是从实现上来说,函数对象是实现了 operate()的类的对象。虽然函数和函数指针也可以归为函数对象,但实现了operate()的类的对象才能保存状态,才能用于STL。
我们直接看定义:
- 一元函数:接受一个参数的函数,如f(x)。如果一元函数返回一个BOOL类型的值,则该函数称为谓词。
- 二元函数:接受2个参数的函数,如f(x,y)。如果二元函数返回一个BOOL值,则该函数称为二元谓词。
之所以给返回布尔类型的函数对象专门命名,是因为谓词是用来为算法判断服务的。
*谓词大体就说这些,后期会在写一篇专门介绍函数对象,和谓词的介绍

通过定制可以看出来,第三个参数需要传入一个函数对象,也就是谓词。实现方式有两种:
第一种:传入一个实现了operator()的类对象;
第二种:传入lambda表达式,lambda表达式本身就是函数对象,可以被stl应用。

更多推荐

C++ find find_if 和 lambda表达式结合的理解和用法