引言
先说几句题外话:对于初学C++的人来说可能看到lambda的介绍之后基本上都没有足够的耐心去看,因为涉及到匿名函数的操作,而我们经常接触到都是确定的函数(有着明确的函数名,当然包含函数句柄的操作),当然自己在一开始学习的时候也是碰到这样的情况,所以现在回想起来还是有必要好好的记录下对lambda理解。
Lambda
首先我们要知道为什么需要lambda,否则看完这篇文章都不知道何去何从。下面是我理解的lambda的用途:
– .在算法头文件包含了许多方便使用的函数(例如for_each,transform),这些函数的操作参数中会调用相应自定义的函数句柄实现用户自定义处理。
– .对于类中的部分短小成员函数实现可以使用lambda,这会是的代码量较少,方便阅读。
基本概念
lambda的概念起源于函数编程,自身属于匿名函数编程。
基本的语法定义如下:
[ capture ] ( params ) mutable exception attribute -> ret { body } (1) [ capture ] ( params ) -> ret { body } (2) [ capture ] ( params ) { body } (3) [ capture ] { body } (4)
解释:
1. capture -> 函数参数类型 2. params -> 操作符重载函数参数 3. mutuble和exception -> 修饰符:mutuble表示传进来的参数可以被修改,对于传值的情况只会修改参数的copy,而不会修改参数本身,exception涉及到异常情况的处理。 4. ->ret 表示返回参数的类型 5. body表示匿名函数的实体部分
对于capture的类型主要包含以下方面:
1、空。没有使用任何函数对象参数。
2、=函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
3、&函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
4、this。函数体内可以使用Lambda所在类中的成员变量。
5、=,a将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。
6、&a将a按引用进行传递。
7、a,&b。将a按值进行传递,b按引用进行传递。
8、=,&a,&b。除a和b按引用进行传递外,其他参数都按值进行传递。
9、&,a,b。除a和b按值进行传递外,其他参数都按引用进行传递。
实验代码
#include<iostream> #include<algorithm> #include<vector> using namespace std; class lambda_id { public: lambda_id() :m_data(20){}; void lambda_test() { std::vector<int> v; v.push_back(1); v.push_back(2); //capture为空 for_each(v.begin(), v.end(), [](int vec){std::cout << vec << endl; }); //capture为= int num = 1; for_each(v.begin(), v.end(), [=](int vec){std::cout << vec + num << endl; }); //capture为& mutable表示传递的值可以被修改 int num_1 = 1; for_each(v.begin(), v.end(), [&](int vec)mutable{std::cout << vec + num_1 << endl; num_1++; }); //capture为this for_each(v.begin(), v.end(), [this](int vec)mutable{std::cout << vec + m_data << endl; }); //capture为res int res = 5; for_each(v.begin(), v.end(), [res](int vec)mutable{std::cout << vec << endl; res++; }); std::cout << res << endl; //capture为=,&res1 int res1 = 5; for_each(v.begin(), v.end(), [=, &res1](int vec){std::cout << vec << endl; ++res1; }); std::cout << res1 << endl; } private: int m_data; }; int _tmain(int argc, _TCHAR* argv[]) { lambda_id result; result.lambda_test(); return 0; }
实验结果如下:
下面给出指定函数返回类型和异常操作example(来源于MSDN):
#include <iostream> #include <functional> int main() { using namespace std; // The following code declares a lambda expression that returns // another lambda expression that adds two numbers. // The returned lambda expression captures parameter x by value. auto addtwointegers = [](int x) -> function<int(int)> { return [=](int y) { return x + y; }; }; // The following code declares a lambda expression that takes another // lambda expression as its argument. // The lambda expression applies the argument z to the function f // and multiplies by 2. auto higherorder = [](const function<int(int)>& f, int z) { return f(z) * 2; }; // Call the lambda expression that is bound to higherorder. auto answer = higherorder(addtwointegers(7), 8); // Print the result, which is (7+8)*2. cout << answer << endl;//结果为30 } 异常处理代码: #include <vector> #include <algorithm> #include <iostream> using namespace std; int main() { // Create a vector that contains 3 elements. vector<int> elements(3); // Create another vector that contains index values. vector<int> indices(3); indices[0] = 0; indices[1] = -1; // This is not a valid subscript. It will trigger an exception. indices[2] = 2; // Use the values from the vector of index values to // fill the elements vector. This example uses a // try/catch block to handle invalid access to the // elements vector. try { for_each(indices.begin(), indices.end(), [&](int index) { elements.at(index) = index; }); } catch (const out_of_range& e) { cerr << "Caught '" << e.what() << "'." << endl; }; }
`输出:
Caught 'invalid vector<T> subscript'.`