函数指针、函数符与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]。

posted @ 2018-07-22 12:07  cpluspluser  阅读(2541)  评论(0编辑  收藏  举报