C++中的lambda函数(匿名函数)[](){}
前言
本博客大部分抄之《C++标准库》书籍
Lambda
C++11引入了lambda,允许inline函数的定义被用作一个参数,或是一个local对象.
Lambda语法
lambda是一份功能定义,可被定义于语句,表达式内部.
最小型的lambda函数没有参数,如下:
[] {
std::cout << "hello lambda" << std::endl;
}
也可以直接调用它:
[] {
std::cout << "hello lambda" << std::endl;
} () //prints "hello lambda"
?或者把它传递给对象,使之能够被调用:
auto l = [] {
std::cout << "hello lambda" << std::endl;
} () //prints "hello lambda"
...
l(); // prints "hello lambda"
lambda总是由一个lambda introducer引入:那是一组方括号,可以指名一个所谓的capture,用来在lambda内部访问"nonstatic外部对象"。如果无需访问外部数据,这组方括号可以为空,就像本例所示。Static对象,诸如std::count式可被使用的。
在lambda introducer和lambda body之间,可以指明参数或mutable,或一份异常明细(exception specification)或attribute specifier以及返回类型,这些可有可无,但如果其中一个出现了,参数所需小括号就必须出现。因此lambda语法也可以是:
[...] {...}
或
[...] (...) mutable throwSpec -> retType {...}
lambda可以拥有参数,指明于小括号内, 就像任何函数一样:
auto l = [] (const std::string &s) {
std::cout << s << std::endl;
};
l("hello lambda"); //prints "hello lambda"
Capture(用以访问外部作用域)
在lambda最开始的方括号内,可以指明一个capture用来处理外部作用域内未被传递为实参的数据,意思就是说让lambda内部函数可以访问外部数据:
- [=] 意味著外部作用域以by value方式传递给lambda。因此当这个lambda被定义时,你可以读取所有外部可读数据(readable data),但是不能改动他们
- [&] 意味着外部作用域以by reference 方式传递给lambda。因此当这个lambda被定义时,你对所有数据的涂写动作都合法,前提是你拥有涂写他们的权力。
也可以个别指明lambda之内所访问的每个对象是by value或者by reference,可以混合不同访问权力,例如:
int x=0;
int y=42;
auto qqq = [x, &y] {
std::cout << "x: " << x << std::endl;
std::cout << "y: " << y << std::endl;
++y; //OK
}
x = y = 77;
qqq();
qqq();
std::cout << "final y:" << y << std::endl;
会产生如下输出:
x: 0
y: 77
x: 0
y: 78
final y:=79
由于x是by value获得一份拷贝,可以在lambda改动它,但是调用++x是通不过编译的,y是by reference,可以改动,其值变化会改变外部,也可以写[=,&y] 取代 [x,&y],其他所有实参通过by value,y是by reference.
为了获得passing by value和passing by reference混合体,可以声明lambda为mutable。
下例中,对象都是by value方式传递,但是在lambda所定义的函数对象内,有权利改变写传入的值
int id = 0;
auto f = [id] () mutable {
std::cout << "id: " << id << std::endl;
++id; // OK
};
id = 42;
f();
f();
f();
std::cout << id << std::endl
输出如下:
id: 0
id: 1
id: 2
42
可以把上面lambda行为视为下面这个function object
Class {
private:
int id;
public:
void operator() () {
std::cout << "id: " << id << std::endl;
++id; //OK
}
};
由于mutable原因,operator()被定义为一个non-const成员函数,意味着对id改写成为可能,由了mutable,lambda变得stateful,即使state是以by value方式传递,如果没有指明mutable,operator()就变成一个const 成员函数,对象就只能读取,因为他们是by value方式传递。
Lambda的类型
lambda类型是不具名function object,每个lambda表达式的类型都是独一无二的,想根据该类型声明对象可以借助template或auto,实在需要写下该类型,可以使用decltype(),例如把一个lambda作为hash function或者ordering准则或sorting准则传递给associative(关联式)容器或unordered(不定序)容器,也可以使用C++标准库提供的std::function<>class template, 指明一个一般化类型给functional programming
如下面例子:
#include<functional>
#include<iostream>
std::function<int(int,int)> returenlambda ()
{
return [] (int x, int y) {
return x*y;
};
}
int main()
{
auto lf = returnLambda();
std::cout << lf(6,7) << std::endl;
}
输出:42
参考文献:
《C++标准库》
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!