一:用法解析


函数原型:

template <class InputIterator, class T>


   InputIterator find (InputIterator first, InputIterator last, const T& val);


功能:

查找[ first , last )范围内第一个与val相等的元素,返回其迭代器;若找不到,返回last。

例子:

// find example
#include <iostream> // std::cout
#include <algorithm> // std::find
#include <vector> // std::vector

int main () {
// using std::find with array and pointer:
int myints[] = { 10, 20, 30, 40 };
int * p;

p = std::find (myints, myints+4, 30);
if (p != myints+4)
std::cout << "Element found in myints: " << *p << '\n';
else
std::cout << "Element not found in myints\n";

// using std::find with vector and iterator:
std::vector<int> myvector (myints,myints+4);
std::vector<int>::iterator it;

it = find (myvector.begin(), myvector.end(), 30);
if (it != myvector.end())
std::cout << "Element found in myvector: " << *it << '\n';
else
std::cout << "Element not found in myvector\n";

return 0;
}

运行如下:


Element found in myints: 30


Element found in myvector: 30


二:源码剖析

源码方面稍微有点麻烦,待我慢慢道来,先把源码贴上。

// TEMPLATE FUNCTION find
template<class _Ty,
class _Ignored> inline
bool _Within_limits(const _Ty& _Val, true_type, true_type, _Ignored)
{ // signed _Elem, signed _Ty
return (SCHAR_MIN <= _Val && _Val <= SCHAR_MAX);
}

template<class _Ty> inline
bool _Within_limits(const _Ty& _Val, true_type, false_type, true_type)
{ // signed _Elem, unsigned _Ty, -1 == static_cast<_Ty>(-1)
return (_Val <= SCHAR_MAX || static_cast<_Ty>(SCHAR_MIN) <= _Val);
}

template<class _Ty> inline
bool _Within_limits(const _Ty& _Val, true_type, false_type, false_type)
{ // signed _Elem, unsigned _Ty, -1 != static_cast<_Ty>(-1)
return (_Val <= SCHAR_MAX);
}

template<class _Ty,
class _Ignored> inline
bool _Within_limits(const _Ty& _Val, false_type, true_type, _Ignored)
{ // unsigned _Elem, signed _Ty
return (0 <= _Val && _Val <= UCHAR_MAX);
}

template<class _Ty,
class _Ignored> inline
bool _Within_limits(const _Ty& _Val, false_type, false_type, _Ignored)
{ // unsigned _Elem, unsigned _Ty
return (_Val <= UCHAR_MAX);
}

template<class _InIt,
class _Ty> inline
bool _Within_limits(_InIt, const _Ty& _Val)
{ // check whether _Val is within the limits of _Elem
typedef typename remove_pointer<_InIt>::type _Elem;
return (_Within_limits(_Val, is_signed<_Elem>(), is_signed<_Ty>(),
integral_constant<bool, -1 == static_cast<_Ty>(-1)>()));
}

template<class _InIt> inline
bool _Within_limits(_InIt, const bool&)
{ // bools are always within the limits of _Elem
return (true);
}

//-------------------------------------------------------------------------------//

template<class _InIt,
class _Ty> inline5
_InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val, true_type)
{ // find first byte matching integral _Val
if (!_Within_limits(_First, _Val))
return (_Last);
_First = static_cast<_InIt>(_CSTD memchr(
_First, static_cast<unsigned char>(_Val), _Last - _First));
return (_First ? _First : _Last);
}

template<class _InIt,
class _Ty> inline
_InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val, false_type)
{ // find first matching _Val
for (; _First != _Last; ++_First)
if (*_First == _Val)
break;
return (_First);
}

//-------------------------------------------------------------------------------//

// TEMPLATE CLASS integral_constant
template<class _Ty,
_Ty _Val>
struct integral_constant
{ // convenient template for integral constant types
static _CONST_DATA _Ty value = _Val;

typedef _Ty value_type;
typedef integral_constant<_Ty, _Val> type;

_CONST_FUN operator value_type() const _NOEXCEPT
{ // return stored value
return (value);
}

_CONST_FUN value_type operator()() const _NOEXCEPT
{ // return stored value
return (value);
}
};

typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;

// TEMPLATE CLASS is_same
template<class _Ty1,
class _Ty2>
struct is_same
: false_type
{ // determine whether _Ty1 and _Ty2 are the same type
};

template<class _Ty1>
struct is_same<_Ty1, _Ty1>
: true_type
{ // determine whether _Ty1 and _Ty2 are the same type
};

template<class _InIt,
class _Ty> inline
_InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val)
{ // find first matching _Val
// activate optimization for pointers to (const) bytes and integral values
typedef integral_constant<bool,
(is_same<_InIt, char *>::value
|| is_same<_InIt, signed char *>::value
|| is_same<_InIt, unsigned char *>::value
|| is_same<_InIt, const char *>::value
|| is_same<_InIt, const signed char *>::value
|| is_same<_InIt, const unsigned char *>::value)
&& is_integral<_Ty>::value
> _Memchr_opt;
return (_Find(_First, _Last, _Val, _Memchr_opt()));
}

template<class _InIt,
class _Ty> inline
_InIt find(_InIt _First, _InIt _Last, const _Ty& _Val)
{ // find first matching _Val
_DEBUG_RANGE(_First, _Last);
return (_Rechecked(_First,
_Find(_Unchecked(_First), _Unchecked(_Last), _Val)));
}

觉得源码挺长的,其实不然,真正的源码比这少了点,我之所以多加了代码是因为find的源码实现调用了其他地方,我也就顺便粘贴过来了。

应该很容易发现,上面的代码我分为了三部分,用两条横线隔开了,为了接下来更清晰的表述,我们姑且从上往下分别命名为:第一部分,第二部分,第三部分。


阅读源码应该从代码底部,一层一层的往上看,好,看源码的最后一个函数,它调用了上一层的函数,那我们再看上一层的函数,有点恐怖的感觉,许多||运算。那我们来看看这个有||运算的函数都做了什么,我可以先告诉你们这个函数是干嘛的,我们知道find函数有三个参数,两个同类型的的迭代器,还有一个特定比较值,那这个有许多||运算的函数其实就是对迭代器的类型做了分类讨论,一共两种情况,一种是指向字符,还有一种不是指向字符的。下面来说下原因。


要理解原因,只要理解两个结构体即可,就是is_same和integral_constant,关于这两个结构体的内容我也贴在源码的第三部分了。我们先来看integral_constant,在这个结构体我们只需关注两句代码,粘贴如下:

static _CONST_DATA _Ty value = _Val;

_CONST_FUN value_type operator()() const _NOEXCEPT
{ // return stored value
return (value);
}

第一句,不用解释了,很简单;第二句,仿函数。


我们先跳过这个结构体,再看下面的两句代码:

typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;

true_type和false_type都是结构体类型,两句代码形式相似,我们就拿true_type来说吧。注意哦,把模板参数带入结构体我们发现,在true_type中,value已被赋值为true了,而在那个仿函数里,也返回了value(其实也就是true)。那么很容易知道false_type就是做了相反的事。


我们再来看is_same结构体,通过源码我们对这个结构体有两个明显的认识,一是继承了true_type/false_type结构体;二是这个结构体有因为模板参数的不同,有两种形式。通过对这个结构体的注释,我们也很容易知道这个结构体是干嘛的:“ determine whether _Ty1 and _Ty2 are the same type ” 。也就是说,true_type代表了 _Ty1 and _Ty2 are the same type;而false_type代表了different type。


好了,现在我们终于可以回过头看下那个有很多||运算的函数了,它在第三部分。我们再次贴出它的源码:

template<class _InIt,
class _Ty> inline
_InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val)
{ // find first matching _Val
// activate optimization for pointers to (const) bytes and integral values
typedef integral_constant<bool,
(is_same<_InIt, char *>::value
|| is_same<_InIt, signed char *>::value
|| is_same<_InIt, unsigned char *>::value
|| is_same<_InIt, const char *>::value
|| is_same<_InIt, const signed char *>::value
|| is_same<_InIt, const unsigned char *>::value)
&& is_integral<_Ty>::value
> _Memchr_opt;
return (_Find(_First, _Last, _Val, _Memchr_opt()));
}

经过上面对integral_constant和is_same两个结构体的解析,我相信你已经看出端倪了。通过is_same判断_InIt参数类型是不是char *,signed char *,unsigned char *等中的一种,并且,注意还有一个&&运算,还要判断_Ty是否是一个整型。若都满足,就相当于 typedef integral_constant<bool,true> _Memchr_opt,进而利用仿函数作为_Find的第四参数。你可能好奇为什么这么做,请接着看:


现在我们来到源码的第二部分,不用读者急着翻哪个是第二部分的代码,我这里贴在下面,就两个函数:

template<class _InIt,
class _Ty> inline
_InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val, true_type)
{ // find first byte matching integral _Val
if (!_Within_limits(_First, _Val))
return (_Last);
_First = static_cast<_InIt>(_CSTD memchr(
_First, static_cast<unsigned char>(_Val), _Last - _First));
return (_First ? _First : _Last);
}

template<class _InIt,
class _Ty> inline
_InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val, false_type)
{ // find first matching _Val
for (; _First != _Last; ++_First)
if (*_First == _Val)
break;
return (_First);
}

注意看这两个函数第四参数,true_type代表_InIt是char *,signed char *,unsigned char *等中的一种,并且_Ty是整型类型的;那么false_type自然是反过来了。

很容易发现第四参数是false_type的,我们很容易看懂代码意思,其实到这里,你已经看到了find函数原始源码实现了,就这么简单。
我们还是重点看第四参数是true_type的,它调用了memchr,这个函数来自头文件<string.h>,读者可以查阅文档,看这个memchr的功能,至此,可以回答上面没解决的一个问题,为什么要分true_type和false_type两种形式的函数,原因很简单,为了效率。这个你只要知道memchr的意思就明白了,话说mem....系列的函数在对字节操作上都很高效,值得源码一探究竟。




源码摘抄自Visual Studio 2015安装目录algorithm文件中。

点击进入目录----> ​​C++源码剖析目录​​