lambda表达式的使用
对于一个对象或者表达式,如果对其可以使用调用运算符,则称他是可调用的,即如果e是可调用的,则我们可以编写代码
e(args),其中args是一个逗号分隔的一个或多个参数的列表,C++中有4种可调用对象,
- 函数
- 函数指针
- 重载了函数调用运算符的类
- lambda表达式
一个lambd表达式表示一个可调用的代码单元,我们可以将其理解为一个未命名的内联函数
一个lambda具有一个返回类型,一个参数列表,和一个函数体,它具有以下的形式
[capture list] (parameter list) -> return type {function body;}
与普通函数不同的是lambda必须使用尾置返回:
C++11定义了一种尾置返回类型,任何函数都可以使用尾置返回,但是这种形式对于返回形式比较复杂的函数最有效
func接受一个int类型的实参,返回一个指针,该指针指向含有10个整数的数组
auto func(int i) -> int*[10]
我们可以忽略参数列表和返回类型,但是必须包含捕获列表和函数体
auto f = [] {return 42;}
向lambda传递参数以及捕获列表
int main()
{
vector<string> ve{"10","dwdw"};
char c = ' ';
ofstream out1("FilePath");
for_each(ve.begin(), ve.end(),
[&out1, c](const string &s){out1 << s << c;});
out1.flush();
return 0;
}
这里lambda捕获 ofstream
的引用(流只能引用,不能复制或者赋值)以及字符c
,接受一个string
的引用。
除此之外我们还可以通过隐式捕获的方式让编译器自己推断出要使用的变量,我们只需要告诉编译器是值传递[=]
还是引用[&]
。
指定lambda的返回类型
默认情况下,如果一个lambd未指定返回类型,并且lambda中包含除return外的其他语句,那么编译器假定这个lambda的返回值是void
的,下面是一个简单的例子,我们使用标准库的transform
算法和一个lambda来将序列中的每一个负数替换为其绝对值
transform(ve.begin(),ve.end(),ve.begin(),
[](int i){return i < 0 ? -i : i;})
但是如果将程序内容改为下面的等价形式,下面的代码就是错误的
//错误代码,lambda函数体含有除return外的语句
//编译器推断这个lambda返回void类型,但是实际上返回了int
transform(ve.begin(),ve.end(),ve.begin(),
[](int i){if(i < 0) return -i;else return i;})
正确的写法应该显式规定返回类型,并且需要使用尾置返回。
//显式指定lambda返回类型为int
transform(ve.begin(),ve.end(),ve.begin(),
[](int i) -> int
{if(i < 0) return -i;else return i;})