1.引入背景
在c/c++中,函数有类型,但不存在对应该类型的变量,只能用指针间接操作。函数是全局的,没有作用域和生存周期的概念(static,namespace只是限定了范围,避免命名冲突)。此外,函数中不能定义函数,即不能嵌套定义。
变量和函数是程序最重要的两个部分。变量有类型,有值,有作用域。而函数有类型,没有值,没有作用域。因此,两者不能一致的处理。
c++11引入lambdas表达式,它是一个变量,可以随时定义函数,有作用域和生命周期,实现了函数的局部化。
2.lambda的形式
C++ 没有为 lambda 表达式引入新的关键字,只是用 [ ]作为表达式的引出符, 后面像普通函数一样,()中声明函数参数,{}中定义函数体。
auto f1 = [](){};
lambda 表达式可以嵌套定义。
auto f1 = []()
{
auto f2 = [](int x) // 嵌套定义lambda表达式
{
return x*x;
};
};
下面是一个直接调用lambda表达式的示例:
#include <iostream>
int main()
{
[]{
std::cout <<"hello lambda" <<std::endl;
}();
return 0;
}
运行结果
hello lambda
实际上,我们很少在定义时直接调用,而是采用如下方式:
#include <iostream>
int main()
{
auto f = []{
std::cout <<"hello lambda" <<std::endl;
};
f();
return 0;
}
运行结果同上。
2.变量捕获
“[=]”表示按值捕获所有外部变量,表达式内部是值的拷贝,并且不能修改;
“[&]”是按引用捕获所有外部变量,内部以引用的方式使用,可以修改;
[]”里明确写出外部变量名,指定按值或者按引用捕获,
2.1捕获值
下面的例子中,变量id以值的方式进入lambda表达式。执行f()时,虽然id已经自增,但是 lambdas捕获id时,id的值是0,因此输出0;main中输出id是自增后的值。
#include <iostream>
int main()
{
int id = 0;
auto f = [id](){
std::cout <<"id = " << id <<std::endl;
};
id++;
f();
std::cout <<"id = " << id <<std::endl;
return 0;
}
运行结果
id = 0
id = 1
2.2捕获引用
变量id以引用的方式进入lambda表达式
#include <iostream>
int main()
{
int id = 0;
auto f = [&id](){
id = id+10;
std::cout <<"id = " << id <<std::endl;
};
id++;
f();
std::cout <<"id = " << id <<std::endl;
return 0;
}
运行结果
id = 11
id = 11
3.泛型的 lambda
在 C++14 里,lambda 表达式可以实现“泛型化”,相当于简化了的模板函数。下面的例子中,整型,浮点型,字符串都可以传给lambda表达式。
#include <iostream>
#include <string>
int main()
{
auto f = [](const auto& x) // 参数使用auto声明,泛型化
{
return x + x;
};
std::string str = "matrix";
std::cout <<"f(3) = " << f(3) << std::endl; // 参数类型是int
std::cout <<"f(0.8) = "<< f(0.8) << std::endl; // 参数类型是double
std::cout << "f(str) = " << f(str) << std::endl; // 参数类型是string
return 0;
}
运行结果
f(3) = 6
f(0.8) = 1.6
f(str) = matrixmatrix