一:用法解析
函数原型:
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++源码剖析目录