Lambda函数
- C++11新增了Lambda函数或Lambda表达式,可以使用匿名函数(无需给函数命名)
- C++11中,对于接受函数指针或仿函数的函数,可以使用匿名函数定义作为其参数
bool func(int x) {return x % 3 == 0;} //普通函数
[] func(int x) {return x % 3 == 0;}
[](double x)->double {int y = x; return x - y;}
- Lambda表达式用[]替代了函数名(匿名);没有声明返回类型,返回类型相当于使用decltype根据返回值推断得到的,若lambda不包含返回语句,推断的返回类型将为void
- 仅当lambda表达式完全有一条返回语句组成时,自动类型推断才管用;否则,需要使用新增的返回类型后置语法
- 函数指针(不同函数)、函数符(仿函数)、Lambda函数的比较:
vector<int> nums(3000);
generate(nums.begin(), nums.end(), std::rand);
bool f3(int x) {return x % 3 == 0;} //函数指针
class f_mod
{
private:
int dv;
public:
f_mod(int d = 1):dv(d){}
bool operator()(int x){return x % dv == 0;} //仿函数
};
int count1 = count_if(nums.begin(), nums.end(), f3);
int count2 = count_if(nums.begin(), nums.end(), f_mod(3));
int count3 = count_if(nums.begin(), nums.end(), [](int x){return x % 3 == 0;}) //Lambda表达式
- 可以给Lambda函数指定一个名称,并且可以像常规函数那样使用它
auto f3 = [](int x){return x % 3 == 0;} //为Lambda表达式指定名称
f3(9); //像常规函数那样使用Lambda表达式
- lambda表达式可以访问作用域内的任何动态变量,要捕获要使用的变量,可将其名称放在中括号内
(1)如果只指定了变量名,将按值访问变量
(2)如果在名称前加上&,将按引用访问变量
(3)[&]能够按引用访问所有动态变量
(4)[=]能够按值访问所有动态变量
int count3 = 0;
for_each(nums.begin(),nums.end(), [&count3](int x){return x % count3 == 0; })
//可以混合两种访问方式:
[=, &count](int x) {return x % count3 == 0;}
包装器
- C++提供了多个包装器(适配器),用于给其他编程接口提供更一致或更合适的接口
- C++11提供了其他的包装器,包括模板
bind
、men_fn
和reference_wrapper
以及包装器function
template <typename T, typename F>
T use_f(T v, F f)
{
return f(v);
}
double dub(double x){return 2.0 * x;}
class Fp{
private:
double z_;
public:
Fp(double z = 1.0):z_(z) {}
double operator()(double p){return z_*p;}
};
int y = 1.21;
use_f(y, dub);
use_f(y, Fp(5.0));
use_f(y, [](double u) {return u*u;})
(1)三次use_f调用会导致模板被实例化了三次,而不是一次,包装器function可以使其只使用use_f()的一个实例而不是三个实例
(2)上述的函数指针、函数对象和lambda表达式都是接受一个double参数并返回一个double值,即调用特征标相同,均为double(double)
(3)调用特征标识由返回类型以及用括号括起并用逗号分隔的参数类型列表定义的
3. 模板function是在头文件functional中声明的,它从调用特征标的角度定义了一个对象,用于包装调用特征标相同的函数指针、函数对象或lambda表达式
#include <functional>
function<double(double)> ef1 = dub;
function<double(double)> ef2 = Fq(5.0);
function<double(double)> ef3 = [](double u){return u*u;}
use_count(y, ef1);
use_count(y, ef2);
use_count(y, ef3); //此时3次调用只会实例化模板1次
//也可以使用匿名对象
use_count(y, function<double(double)>(dub));
//也可以通过修改模板,让形参f的类型与原始实参匹配
T use_f(T v, std::function<T(T)> f){
return f(v);
}
use_f(y, dub); //直接这样调用即可