函數指針、函數符與Lambda表達式


先來看這樣一段代碼:

#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]。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM