30分钟掌握STL系列(五)
这一节讲一讲STL中的函数与函数对象。
STL中,函数被称为算法,也就是说它们和标准C库函数相比,它们更为通用。STL算
法通过重载operator()函数实现为模板类或模板函数。这些类用于创建函数对象,对
容器中的数据进行各种各样的操作。下面的几节解释如何使用函数和函数对象。
函数和断言
经常需要对容器中的数据进行用户自定义的操作。例如,你可能希望遍历一个容器中
所有对象的STL算法能够回调自己的函数。例如
#i nclude <iostream.h>
#i nclude <stdlib.h> // Need random(), srandom()
#i nclude <time.h> // Need time()
#i nclude <vector> // Need vector
#i nclude <algorithm> // Need for_each()
#define VSIZE 24 // Size of vector
vector<long> v(VSIZE); // Vector object
// Function prototypes
void initialize(long &ri);
void show(const long &ri);
bool isMinus(const long &ri); // Predicate function
int main()
{
srandom( time(NULL) ); // Seed random generator
for_each(v.begin(), v.end(), initialize);//调用普通函数
cout << "Vector of signed long integers" << endl;
for_each(v.begin(), v.end(), show);
cout << endl;
// Use predicate function to count negative values
//
int count = 0;
vector<long>::iterator p;
p = find_if(v.begin(), v.end(), isMinus);//调用断言函数
while (p != v.end()) {
count++;
p = find_if(p + 1, v.end(), isMinus);
}
cout << "Number of values: " << VSIZE << endl;
cout << "Negative values : " << count << endl;
return 0;
}
// Set ri to a signed integer value
void initialize(long &ri)
{
ri = ( random() - (RAND_MAX / 2) );
// ri = random();
}
// Display value of ri
void show(const long &ri)
{
cout << ri << " ";
}
// Returns true if ri is less than 0
bool isMinus(const long &ri)
{
return (ri < 0);
}
所谓断言函数,就是返回bool值的函数。
函数对象
除了给STL算法传递一个回调函数,你还可能需要传递一个类对象以便执行更复杂的
操作。这样的一个对象就叫做函数对象。实际上函数对象就是一个类,但它和回调函
数一样可以被回调。例如,在函数对象每次被for_each()或find_if()函数调用时可
以保留统计信息。函数对象是通过重载operator()()实现的。如果TanyClass定义了
opeator()(),那么就可以这么使用:
TAnyClass object; // Construct object
object(); // Calls TAnyClass::operator()() function
for_each(v.begin(), v.end(), object);
STL定义了几个函数对象。由于它们是模板,所以能够用于任何类型,包括C/C++固有
的数据类型,如long。有些函数对象从名字中就可以看出它的用途,如plus()和multipl
ies
()。类似的greater()和less-equal()用于比较两个值。
注意
有些版本的ANSI C++定义了times()函数对象,而GNU C++把它命名为multiplies()。
使用时必须包含头文件<functional>。
一个有用的函数对象的应用是accumulate() 算法。该函数计算容器中所有值的总和
。记住这样的值不一定是简单的类型,通过重载operator+(),也可以是类对象。
//accum.cpp
#i nclude <iostream.h>
#i nclude <numeric> // Need accumulate()
#i nclude <vector> // Need vector
#i nclude <functional> // Need multiplies() (or times())
#define MAX 10
vector<long> v(MAX); // Vector object
int main()
{
// Fill vector using conventional loop
//
for (int i = 0; i < MAX; i++)
v[i] = i + 1;
// Accumulate the sum of contained values
//
long sum =
accumulate(v.begin(), v.end(), 0);
cout << "Sum of values == " << sum << endl;
// Accumulate the product of contained values
//
long product =
accumulate(v.begin(), v.end(), 1, multiplies<long>());//注意这行
cout << "Product of values == " << product << endl;
return 0;
}
编译输出如下:
$ g++ accum.cpp
$ ./a.out
Sum of values == 55
Product of values == 3628800
『注意使用了函数对象的accumulate()的用法。accumulate() 在内部将每个容器中
的对象和第三个参数作为multiplies函数对象的参数,multiplies(1,v)计算乘积。VC
中的这些模板的源代码如下:
// TEMPLATE FUNCTION accumulate
template<class _II, class _Ty> inline
_Ty accumulate(_II _F, _II _L, _Ty _V)
{for (; _F != _L; ++_F)
_V = _V + *_F;
return (_V); }
// TEMPLATE FUNCTION accumulate WITH BINOP
template<class _II, class _Ty, class _Bop> inline
_Ty accumulate(_II _F, _II _L, _Ty _V, _Bop _B)
{for (; _F != _L; ++_F)
_V = _B(_V, *_F);
return (_V); }
// TEMPLATE STRUCT binary_function
template<class _A1, class _A2, class _R>
struct binary_function {
typedef _A1 first_argument_type;
typedef _A2 second_argument_type;
typedef _R result_type;
};
// TEMPLATE STRUCT multiplies
template<class _Ty>
struct multiplies : binary_function<_Ty, _Ty, _Ty> {
_Ty operator()(const _Ty& _X, const _Ty& _Y) const
{return (_X * _Y); }
};