Function object定义:
Function object是一个对象,不过它的行为表现像函数。一般而言,它是由一个重载了operator()的类所实例化得来的对象。
Function object的涵义比通常意义上的函数更广泛,因为它可以在多次调用之间保持某种“状态”——这和静态局部变量有异曲同工之妙;不过这种“状态”还可以被初始化,还可以从外面来检测,这可要比静态局部变量强了。我们来看一个例子:
- class Sum {
- int val;
- public:
- Sum(int i) :val(i) { }
- operator int() const { return val; } // extract value
- int operator()(int i) { return val+=i; } // application
- };
- void f(vector<int> v)
- {
- Sum s = 0; // initial value 0
- s = for_each(v.begin(), v.end(), s); // gather the sum of all elements
- cout << "the sum is " << s << "/n";
- // or even:
- cout << "the sum is " << for_each(v.begin(), v.end(), Sum(0)) << "/n";
- }
这里我要提请大家注意:一个function object可被漂亮地内联化(inlining),因为对于编译器而言,没有讨厌的指针来混淆视听,所以这样的优化很容易进行。[译注:这指的是将operator()定义为内联函数,可以带来效率的提高。] 作为对比,编译器几乎不可能通过优化将“通过函数指针调用函数”这一步骤所花的开销省掉,至少目前如此。
在标准库中function objects被广泛使用,这给标准库带来了极大的灵活性和可扩展性。
下面再看一个例子:
- #include <iostream>
- #include <vector>
- #include <algorithm>
- using namespace std;
- void printInt (int elem)
- {
- cout << elem << ' ' ;
- }
- int main()
- {
- vector<int> coll;
- //insert elements from 1 to 9
- for (int i=1; i<=9; ++i) {
- coll.push_back(i);
- }
- //print all elements
- for_each (coll.begin(), coll.end(),printInt);
- cout << endl;
- }
对于这个例子,for_each()的第三个参数,调用了printInt这个函数。在看下面的例子:
- #include <iostream>
- #include <vector>
- #include <algorithm>
- using namespace std;
- //simple function object that prints the passed argument
- class PrintInt {
- public:
- void operator() (int elem) const {
- cout << elem << ' ';
- }
- };
- int main()
- {
- vector<int> coll;
- //insert elements from 1 to 9
- for (int i=1; i<=9; ++i) {
- coll.push_back(i);
- }
- //print all elements
- for_each (coll.begin(), coll.end(), PrintInt());
- cout << endl;
- }
在这个例子中,for_each()的第三个参数就是函数对象。
那么这到底有什么区别呢?也许从上面的代码中还看不出,但是,请继续看下面的例子:
- //对每一个element加10;
- void add10 (int& elem)
- {
- elem += 10;
- }
- void fl()
- {
- vector<int> coll;
- ...
- for_each (coll.begin(), coll.end(), add10);
- }
这样看起来似乎很好,但是,如果突然要求变了,要求对每一个element改成加9;那么,可能想到的办法是改写函数
void add9 (int& elem)
{
elem +=9;
}
哦,那么要求又改成+8、+7…… -3等等,总不至于对于每一个都重新写一个函数吧?虽然可行,但是违背
范型变成的思想。也许有新的办法:
- template <int theValue>
- void add (int& elem)
- {
- elem += theValue;
- }
- void f1()
- {
- vector<int> coll;
- ...
- for_each (coll.begin() , coll.end(), //range
- add<10>); //operation
- }
但是,如果连类型(int)都变了(如改成float),那该怎么实现呢?哦,用一般的函数应该不能实现了吧?
但是如果用function object思想,就可以实现,看下面的代码:
- template <class T>
- class AddValue {
- private:
- T theValue;
- public:
- AddValue(T v) : theValue(v) {
- }
- void operator() (T& elem) const {
- elem += theValue;
- }
- };
现在这个类就可以实现多个类型的相加形式了。
因此可以总结在用函数对象时,可以更加满足了STL的范型编程思想。