先來看這樣一段代碼:
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <iterator>
int main()
{
std::vector<int> v(500);
std::generate(v.begin(), v.end(), std::rand);
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, "\t"));
std::cin.get();
return 0;
}
std::generate的第三個參數是個不接受任何參數的函數對象,這里,該函數對象是一個指向std::rand的指針。利用這個函數,為v隨機初始化了500個值。
現在,若要統計這500個數里面有多少個可以被5整除和被15整除的,我們可以使用std::count_if:
bool f5(int x)
{
return x % 5 == 0;
}
bool f15(int x)
{
return x % 15 == 0;
}
int count = std::count_if(v.begin(), v.end(), f5);
int count1 = std::count_if(v.begin(), v.end(), f15);
std::cout << count << " " << count1 << std::endl;
f5和f15是通過函數指針的方式傳進去的,那么如何通過函數符來完成呢?函數符是一個類對象,通過類方法operator()(),我們可以使用同一個函數符來完成這兩項功能。
class fun
{
public:
fun(int x = 1) : mnum(x) {}
bool operator()(int x) { return x % mnum == 0; }
private:
int mnum;
};
通過構造函數,便可以根據傳進來的值來決定實際操作。現在,可以這樣調用:
int count2 = std::count_if(v.begin(), v.end(), fun(5));
int count3 = std::count_if(v.begin(), v.end(), fun(15));
參數fun(5)創建了一個對象,將5作為了munm的初始值,而std::count_if()則使用該對象來調用operator()()。
還可以使用lambda來完成:
int count4 = std::count_if(v.begin(), v.end(),
[](int x) {
return x % 5 == 0;
});
使用lambda表達式可以替換函數指針或函數符構造函數。
僅當lambda表達式完全由一條返回語句組成時,自動類型推斷才有用;否則,則需使用返回類型后置語法:
[](int x) ->int { int y = x; return x - y; }
對於相同的功能,也並非要編寫表達式兩次,我們可以給lambda指定一個名稱:
auto mod5 = [](int x) { return x % 3 == 0; }
count4 = std::count_if(v.begin(), v.end(), mod5);
count5 = std::count_if(v1.begin(), v1.end(), mod5);
亦可像使用平常函數那樣使用有名稱的lambda:
bool ret = mod5(13);
對於這有一種方式,函數指針方法阻止了內聯,因為編譯器傳統上不會內聯其地址被獲取的函數,因為函數地址意味着非內聯函數。而函數符和lambda通常不會阻止內聯。
lambda還可以捕獲作用域內的任何動態變量,要捕獲的變量可將其放在[]內。使用[=]表示按值傳遞所有動態的變量,使用[&]可以按引用訪問所有的動態變量,也可單獨使用[&x],[=x],亦可混合使用[x, &count]。