C++11 Lambda表达式
今天学习了C++11引入的Lambda表达式,Lambda在使用上有很多的方便之处。我们可以将之用于函数的回调,操作的封装的等地方。如果我们有Objective-c的经验的话,其实我可以将Lambda表达式和Block进行对比学习,两者有很多的相似之处。
优势
根据对Lambda的了解,发现其用途和函数指针有太多的相似之处,甚至可以理解为功能重叠。那么为什么在C++11中还要引入Lambda表达式呢?
1. 函数指针是类型不安全的
C语言的函数指针就是一个地址变量,在赋值和调用的时候没有任何类型检查。任何一种函数指针都可以转型为其他类型的函数指针, 当转型回来时,与原函数指针相同。必须由开发者自己保证正确的类型。函数指针无法提前在编译器给出错误提示。
2. bind能保证类型安全,但对于绑定变量的内容,需要程序员保证有效性
综合上述原因,引入Lambda表达式还是很有必要的
Lambda表达式
我们将从Lambda表达式的定义,调用,传递几个方面进行阐述
Lambda表达式的定义
Lambda表达式的定义我们可以根据下图给出准确描述
- 表示要捕获的作用域内的变量
· 为空时表示不捕获任何变量
· =表示按值传递的捕获,表示捕获作用域内所有的变量
· 直接输入变量名,表示指定捕获特定的变量
· &变量名 表示按引入捕获 - 表示传入参数的列表
- 表示捕获的变量是否在Lambda表达式中可修改
- Lambda表达式抛出的异常
- Lambda表达式的返回值
- Lambda表达式函数体
Lambda表达式使用
了解了Lambda表达式的定义,我们来看看Lambda表达式的使用
不捕获任何变量的
int main()
{
//定义一个不捕获任何变量,返回值为int的Lambda表达式
auto lambda = []() -> int{
std::cout << "my name is " << "codecooker" << std::endl;
return 1;
};
//调用我们定义的Lambda表达式,和调用不同函数没什么区别
lambda();
return 0;
}
编译运行
g++ lambda.cpp -std=c++11 -o lambda
./lambda
output:my name is codecooker
Lambda表达式基础用法
int main()
{
string name = "Powell";
//按照前面描述的定义规则,我们需要捕获作用域内的name变量,这里我们用=号,表示按照值传递捕获
auto lambda = [=]() -> int{
std::cout << "my name is " << name << std::endl;
return 1;
};
lambda();
return 0;
}
output:my name is Powell
下来我们尝试着修改捕获的变量值,代码如下
auto lambda = [=]() -> int{
name = "codecooker";
std::cout << "my name is " << name << std::endl;
return 1;
};
发现编译报错
candidate function not viable: 'this' argument has type 'const string'
(aka 'const basic_string<char,char_traits<char>, allocator<char> >'),
but method is not marked const basic_string& operator=(const basic_string& __str);
这时我们的mutable就派上了用场,修改代码如下
auto lambda = [=]() mutable -> int{
name = "codecooker";
std::cout << "my name is " << name << std::endl;
return 1;
};
output:my name is codecooker
然而问题并没有结束,看下述代码
int main()
{
string name = "Powell";
//按照前面描述的定义规则,我们需要捕获作用域内的name变量,这里我们用=号,表示按照值传递捕获
auto lambda = [=]() mutable -> int{
name = "codecooker";
std::cout << "my name is " << name << std::endl;
return 1;
};
lambda();
std::cout << "my origin name is " << name << std::endl;
return 0;
}
output:
my name is codecooker
my origin name is Powell
其实这里即使用了mutable修饰我们的Lambda表达式,在Lambda表达式内修改的也只是name变量的一份copy,如果我们需要在Lambda表达式内修改捕获的变量,我们则需要按照引用捕获,如下
auto lambda = [&]() mutable -> int{
name = "codecooker";
std::cout << "my name is " << name << std::endl;
return 1;
};
output:
my name is codecooker
my origin name is codecooker
下面我们来看怎么给Lambda表达式传递参数
int age = 27;
auto lambda = [&](int age) mutable -> int{
name = "codecooker";
std::cout << "my name is " << name << std::endl;
std::cout << "my age is " << age << std::endl;
return 1;
};
lambda(age);
output:
my name is codecooker
my age is 27
和普通函数传递参数是一样的,大家可以发挥想象力
Lambda表达式作为参数
前面已经说过Lambda表达式是std::function类型的变量,既然是变量那么必须可以作为参数进行传递,有了上边的描述,直接上代码
#include <iostream>
#include <string>
#include <functional>
using std::function;
using std::string;
void foo(function<int(int)> lambda);
int main()
{
string name = "Powell";
int age = 27;
auto lambda = [&](int age) mutable -> int{
name = "codecooker";
std::cout << "my name is " << name << std::endl;
std::cout << "my age is " << age << std::endl;
return 1;
};
foo(lambda);
return 0;
}
void foo(function<int(int age)> lambda) {
int age = 27;
auto result = lambda(age);
std::cout << "result is " << result << std::endl;
}
output:
my name is codecooker
my age is 27
result is 1
至此,关于Lambda表达式的相关内容相信大家已经了然于胸了。