Lambda 表达式不仅具有函数指针的灵活性,还可以通过捕获局部变量提高可扩展性。本文介绍 Lambda 表达式的语法和用法。
简介
Lambda 可能是最新的 C++11 标准的典型特性之一。Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。
当一个函数需要将另一个函数用作参数时,可以使用 Lambda。例如,C qsort() 函数接受一个指向比较函数的指针,如清单 1 所示。
#include <stdlib.h> #include <stdio.h> static int intcompare(const void *p1, const void *p2) { int i = *((int *)p1); int j = *((int *)p2); return (i < j) ; } int main() { int a[10] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; qsort((void *)a, 10, sizeof (int), intcompare); for (int i = 0; i < 10; i++) { printf("%d ", a[i]); } printf(" "); return 0; }
清单 1
清单 1 中的代码有以下几点不足:
- 比较函数需要单独声明。这增加了将错误的比较函数传递给 qsort() 操作的风险。
- 比较函数接受 void * 参数,因此缺失了某种程度的类型检查。
- 比较函数看不到任何局部作用的变量。因此,如果存在其他影响排序的因素,必须在更大范围内声明。
清单 2 显示重新编写后的清单 1 中的示例,将 C++ std::sort() 算法与 lambda 表达式结合使用。由于 std::sort() 是一个模板,因此会保留所有类型信息。注意如何在通常出现函数名的位置编写 lambda 表达式。
#include <algorithm> int main() { int a[10] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; std::sort( a, &a[10], [](int x, int y){ return x < y; } ); for(int i=0; i<10; i++) { printf("%i ", a[i]); } printf(" "); return 0; }
清单 2
Lambda 表达式的基本语法
Lambda 表达式本质上与函数声明非常类似。我们可以提取清单 2 中的 lambda 表达式,详加说明。提取的 lambda 表达式如清单 3 所示:
[](int x, int y){ return x < y ; }
清单 3
如果我们将 lambda 表达式比作函数,可以看到它与函数名对应的是一对空的方括号,即捕获表达式。这些括号表示后面跟着一个 lambda 表达式。这些方括号不必为空;稍后将讨论其内容。
如果 lambda 主体只含一个返回类型,则暗示返回的表达式类型为 lambda 返回类型。如果要显式指定返回类型,需使用新的 C++11 语法表示函数声明中的后置返回类型。对于返回类型 T 的普通函数,您可以这样编写:
auto foo(...) -> T { ... }
对于 lambda,您需要要这样编写:
[] (...) -> T { ... }
lambda 表达式的其余部分与常规 C 或 C++ 函数主体类似。
将 Lambda 传递到函数指针
C++11 标准库中有一个名为 function 的模板,它可以接受指定类型的函数或者具有匹配的返回类型和参数列表的 lambda。这将产生一个指向函数类型的指针,例如,清单 4 可用作函数参数类型,接受 int 参数,返回 void。您可以向其传递任何类似匹配函数或 lambda 的内容。
std::function<void(int)>
#include <iostream> #include <vector> #include <algorithm> using namespace std; bool cmp(int a, int b) { return a < b; } int main() { vector<int> myvec{ 3, 2, 5, 7, 3, 2 }; vector<int> lbvec(myvec); sort(myvec.begin(), myvec.end(), cmp); // 旧式做法 cout << "predicate function:" << endl; for (int it : myvec) cout << it << ' '; cout << endl; sort(lbvec.begin(), lbvec.end(), [](int a, int b) -> bool { return a < b; }); // Lambda表达式 cout << "lambda expression:" << endl; for (int it : lbvec) cout << it << ' '; }
#include <iostream> #include <algorithm> using namespace std; int main() { int a = 900; auto f = [a] { cout << a << endl; }; cout << ++a << endl; return 0; }
root@ubuntu:~/c++# g++ -std=c++11 lam.cpp -o lam root@ubuntu:~/c++# ./lam 901
#include <iostream> #include <algorithm> using namespace std; int main() { int a = 900; auto f = [a] { cout << ++a << endl; }; f(); cout << ++a << endl; return 0; }
root@ubuntu:~/c++# g++ -std=c++11 lam.cpp -o lam lam.cpp: In lambda function: lam.cpp:7:31: error: increment of read-only variable ‘a’ auto f = [a] { cout << ++a << endl; };
#include <iostream> #include <algorithm> using namespace std; int main() { int a = 900; auto f = [&a] { cout << ++a << endl; }; f(); cout << ++a << endl; return 0; }
root@ubuntu:~/c++# g++ -std=c++11 lam.cpp -o lam root@ubuntu:~/c++# ./lam 901 902
#include <iostream> #include <algorithm> using namespace std; int main() { int a = 900; auto f = [](int a) mutable { cout << ++a << endl; }; f(300); cout << ++a << endl; return 0; }
root@ubuntu:~/c++# g++ -std=c++11 lam.cpp -o lam root@ubuntu:~/c++# ./lam 301 901 root@ubuntu:~/c++#
#include <iostream> #include <algorithm> using namespace std; int main() { int a = 900; auto f = [](int b) { cout << ++a + b << endl; }; f(300); cout << ++a << endl; return 0; } ~
lam.cpp: In lambda function: lam.cpp:7:37: error: ‘a’ is not captured auto f = [](int b) { cout << ++a + b << endl; }; ^ lam.cpp:7:16: note: the lambda has no capture-default auto f = [](int b) { cout << ++a + b << endl; }; ^ lam.cpp:6:10: note: ‘int a’ declared here int a = 900; ^
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int a = 900;
[](int a) mutable { cout << ++a << endl; }(20);
cout << ++a << endl;
return 0;
}
root@ubuntu:~/c++# g++ -std=c++11 lam.cpp -o lam root@ubuntu:~/c++# ./lam 21 901
#include <iostream> #include <algorithm> #include<functional> using namespace std; int main() { int a = 900; function<int(int x)> f_display_42 = [](int x) { return ++x; }; cout << f_display_42(44) << endl; cout << ++a << endl; return 0; }
root@ubuntu:~/c++# g++ -std=c++11 lam.cpp -o lam root@ubuntu:~/c++# ./lam 45 901
#include <iostream> #include <algorithm> #include<functional> using namespace std; int main() { int a = 900; function<int(int x)> f_display_42 = [a](int x) { return a+x; }; cout << f_display_42(44) << endl; cout << ++a << endl; return 0; }
root@ubuntu:~/c++# g++ -std=c++11 lam.cpp -o lam root@ubuntu:~/c++# ./lam 944 901
捕获形式 | 说明 |
---|---|
[] | 不捕获任何外部变量 |
[变量名, …] | 默认以值得形式捕获指定的多个外部变量(用逗号分隔),如果引用捕获,需要显示声明(使用&说明符) |
[this] | 以值的形式捕获this指针 |
[=] | 以值的形式捕获所有外部变量 |
[&] | 以引用形式捕获所有外部变量 |
[=, &x] | 变量x以引用形式捕获,其余变量以传值形式捕获 |
[&, x] | 变量x以值的形式捕获,其余变量以引用形式捕获 |
https://www.cnblogs.com/DswCnblog/p/5629165.html
https://www.oracle.com/cn/servers/technologies/howto-use-lambda-exp-cpp11.html