本博客大部分抄之《C++标准库》书籍
C++11引入了lambda,允许inline函数的定义被用作一个参数,或是一个local对象.
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"
在lambda最开始的方括号内,可以指明一个capture用来处理外部作用域内未被传递为实参的数据,意思就是说让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类型是不具名function object,每个lambda表达式的类型都是独一无二的,想根据该类型声明对象可以借助template或auto,实在需要写下该类型,可以使用decltype(),例如把一个lambda作为hash function或者ordering准则或sorting准则传递给associative(关联式)容器或unordered(不定序)容器,也可以使用C++标准库提供的std::function<>class template, 指明一个一般化类型给functional programming
如下面例子:
#include
#include
std::function returenlambda ()
{
return [] (int x, int y) {
return x*y;
};
}
int main()
{
auto lf = returnLambda();
std::cout << lf(6,7) << std::endl;
}
输出:42
《C++标准库》