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