|

楼主 |
发表于 2009-9-30 00:34:27
|
显示全部楼层
所谓断言函数,就是返回bool值的函数。
函数对象 除了给STL算法传递一个回调函数,你还可能需要传递一个类对象以便执行更复杂的操作。这样的一个对象就叫做函数对象。实际上函数对象就是一个类,但它和回调函数一样可以被回调。例如,在函数对象每次被for_each()或find_if()函数调用时可以保留统计信息。函数对象是通过重载 operator()()实现的。如果TanyClass定义了opeator()(),那么就可以这么使用:
TAnyClass object; // Construct object object(); // Calls TAnyClass:perator()() function for_each(v.begin(), v.end(), object); STL定义了几个函数对象。由于它们是模板,所以能够用于任何类型,包括C/C++固有的数据类型,如long。有些函数对象从名字中就可以看出它的用途,如plus()和multiplies()。类似的greater()和less-equal()用于比较两个值。
注意
有些版本的ANSI C++定义了times()函数对象,而GNU C++把它命名为multiplies()。使用时必须包含头文件<functional>。
一个有用的函数对象的应用是accumulate() 算法。该函数计算容器中所有值的总和。记住这样的值不一定是简单的类型,通过重载operator+(),也可以是类对象。
Listing 8. accum.cpp
#include <iostream.h> #include <numeric> // Need accumulate() #include <vector> // Need vector #include <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 + 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); }
};
引言:如果你想深入了解STL到底是怎么实现的,最好的办法是写个简单的程序,将程序中涉及到的模板源码给copy下来,稍作整理,就能看懂了。所以没有必要去买什么《STL源码剖析》之类的书籍,那些书可能反而浪费时间。』
发生器函数对象 有一类有用的函数对象是“发生器”(generator)。这类函数有自己的内存,也就是说它能够从先前的调用中记住一个值。例如随机数发生器函数。
普通的C程序员使用静态或全局变量 “记忆”上次调用的结果。但这样做的缺点是该函数无法和它的数据相分离『还有个缺点是要用TLS才能线程安全』。显然,使用类来封装一块:“内存”更安全可靠。先看一下例子:
Listing 9. randfunc.cpp
#include <iostream.h> #include <stdlib.h> // Need random(), srandom() #include <time.h> // Need time() #include <algorithm> // Need random_shuffle() #include <vector> // Need vector #include <functional> // Need ptr_fun()
using namespace std;
// Data to randomize int iarray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; vector<int> v(iarray, iarray + 10);
// Function prototypes void Display(vector<int>& vr, const char *s); unsigned int RandInt(const unsigned int n);
int main() { srandom( time(NULL) ; // Seed random generator Display(v, "Before shuffle:");
pointer_to_unary_function<unsigned int, unsigned int> ptr_RandInt = ptr_fun(RandInt); // Pointer to RandInt()//注意这行 random_shuffle(v.begin(), v.end(), ptr_RandInt);
Display(v, "After shuffle:"); return 0; }
// Display contents of vector vr void Display(vector<int>& vr, const char *s) { cout << endl << s << endl; copy(vr.begin(), vr.end(), ostream_iterator<int>(cout, " ")); cout << endl; }
// Return next random value in sequence modulo n unsigned int RandInt(const unsigned int n) { return random() % n; } 编译运行结果如下:
$ g++ randfunc.cpp $ ./a.out Before shuffle: 1 2 3 4 5 6 7 8 9 10 After shuffle: 6 7 2 8 3 5 10 1 9 4 首先用下面的语句申明一个对象:
pointer_to_unary_function<unsigned int, unsigned int> ptr_RandInt = ptr_fun(RandInt); 这儿使用STL的单目函数模板定义了一个变量ptr_RandInt,并将地址初始化到我们的函数RandInt()。单目函数接受一个参数,并返回一个值。现在random_shuffle()可以如下调用:
random_shuffle(v.begin(), v.end(), ptr_RandInt); 在本例子中,发生器只是简单的调用rand()函数。
关于常量引用的一点小麻烦(不翻译了,VC下将例子中的const去掉)
发生器函数类对象 下面的例子说明发生器函数类对象的使用。
Listing 10. fiborand.cpp
#include <iostream.h> #include <algorithm> // Need random_shuffle() #include <vector> // Need vector #include <functional> // Need unary_function
using namespace std;
// Data to randomize int iarray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; vector<int> v(iarray, iarray + 10);
// Function prototype void Display(vector<int>& vr, const char *s);
// The FiboRand template function-object class template <class Arg> class FiboRand : public unary_function<Arg, Arg> { int i, j; Arg sequence[18]; public: FiboRand(); Arg operator()(const Arg& arg); };
void main() { FiboRand<int> fibogen; // Construct generator object cout << "Fibonacci random number generator" << endl; cout << "using random_shuffle and a function object" << endl; Display(v, "Before shuffle:"); random_shuffle(v.begin(), v.end(), fibogen); Display(v, "After shuffle:"); }
// Display contents of vector vr void Display(vector<int>& vr, const char *s) { cout << endl << s << endl; copy(vr.begin(), vr.end(), ostream_iterator<int>(cout, " ")); cout << endl; }
// FiboRand class constructor template<class Arg> FiboRand<Arg>::FiboRand() { sequence[17] = 1; sequence[16] = 2; for (int n = 15; n > 0; n—) sequence[n] = sequence[n + 1] + sequence[n + 2]; i = 17; j = 5; }
// FiboRand class function operator template<class Arg> Arg FiboRand<Arg>:perator()(const Arg& arg) { Arg k = sequence + sequence[j]; sequence = k; i--; j--; if (i == 0) i = 17; if (j == 0) j = 17; return k % arg; } 编译运行输出如下:
$ g++ fiborand.cpp $ ./a.out Fibonacci random number generator using random_shuffle and a function object Before shuffle: 1 2 3 4 5 6 7 8 9 10 After shuffle: 6 8 5 4 3 7 10 1 9 |
|