C++ lambda表达式
2017-04-08 21:55
288 查看
C++11及之后的lambda表达式是一个强大的工具,它可以表示一个可调用的代码单元。可以理解为一个未命名的内联函数。一个lambda表达式具有如下形式:
我们可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体。
lambda表达式常常和for_each以及迭代器一起使用。如下,需要对vector中的每一个值求平方:
这是输出的结果:
当然了,除了这个方法,还可以用函数指针来解决这个问题:
最后的结果是一样的。
这个在Python中直接使用map就能达到相同的效果:
map中第一个参数表示需要实施的函数,而第二个参数表示函数实施的对象。而对于lambda,和C++比较相似,但语法不一样。
下面对lambda中的捕获列表做一些说明,捕获列表可以是值传递,即传入一个拷贝,或是引用传递,即传递的是一个引用,对引用进行的操作会直接影响到被引用的对象的值。
下面举个例子说明:
第一个是值传入,最后输出的是对之前v1的拷贝的值,v1的改变并不会对最后j的值造成影响,所以最后j的值还是42。而第二个例子中传入的引用,这时此引用指向被引用的对象,即v2,于是它们幸福地绑定在一起了,后面对v2进行了变化,那么引用也会跟随,即最后k的值也变成了2。
其实也可以对传入的捕获值进行变化,对于值传递,需要加一个关键词mutable。而对于引用传递,可不可以变化,要看传入值是不是const类型,如果是,则不能;如果不是,则可以。那么看下面的例子:
这里分别输出了调用lambda表达式的值和被捕获的值。对于值传递,改变了v1的拷贝的值,于是j等于了43,而v1还是42;对于引用传递,由于绑定的原因,对引用的改变,那么被引用的变量的值也会变,所以最后k和v2的值都变成了3。
[capture list] (parameter list) -> return type { function body }
我们可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体。
auto f = [] { return 42; }; cout << f() << endl; // print 42
lambda表达式常常和for_each以及迭代器一起使用。如下,需要对vector中的每一个值求平方:
#include <iostream> using namespace std; int main(int argc, const char * argv[]) { vector<int> test = {3,2,5}; for(auto v: test) cout << v << " "; cout << endl; for_each(test.begin(), test.end(), [] (int& a) { a *= a; }); for(auto v: test) cout << v << " "; cout << endl; return 0; }
这是输出的结果:
当然了,除了这个方法,还可以用函数指针来解决这个问题:
#include <iostream> using namespace std; typedef int (*pf)(int); template <class T> void square(vector<T>& vec, pf func) { for (auto &v: vec) v *= v; // need to use reference } int main(int argc, const char * argv[]) { vector<int> test = {3,2,5}; for(auto v: test) cout << v << " "; cout << endl; square(test, squareTest); //for_each(test.begin(), test.end(), [](int& a){ a *= a; }); for(auto v: test) cout << v << " "; cout << endl; return 0; }
最后的结果是一样的。
这个在Python中直接使用map就能达到相同的效果:
def squareTest(a): return a**2 test = [3,2,5] print(test) print(map(squareTest, test)) # print(map(lambda a : a**2 , test)) # can use lambda as well
map中第一个参数表示需要实施的函数,而第二个参数表示函数实施的对象。而对于lambda,和C++比较相似,但语法不一样。
下面对lambda中的捕获列表做一些说明,捕获列表可以是值传递,即传入一个拷贝,或是引用传递,即传递的是一个引用,对引用进行的操作会直接影响到被引用的对象的值。
下面举个例子说明:
int main(int argc, const char * argv[]) { size_t v1 = 42; auto f = [v1] { return v1; }; v1 = 2; auto j = f(); cout << j << endl; // j = 42 size_t v2 = 42; auto f1 = [&v2] { return v2; }; v2 = 2; auto k = f1(); cout << k << endl; // k = 2 return 0; }
第一个是值传入,最后输出的是对之前v1的拷贝的值,v1的改变并不会对最后j的值造成影响,所以最后j的值还是42。而第二个例子中传入的引用,这时此引用指向被引用的对象,即v2,于是它们幸福地绑定在一起了,后面对v2进行了变化,那么引用也会跟随,即最后k的值也变成了2。
其实也可以对传入的捕获值进行变化,对于值传递,需要加一个关键词mutable。而对于引用传递,可不可以变化,要看传入值是不是const类型,如果是,则不能;如果不是,则可以。那么看下面的例子:
int main(int argc, const char * argv[]) { size_t v1 = 42; auto f = [v1] () mutable { return ++v1; }; v1 = 2; auto j = f(); cout << j << endl; // j = 43 cout << v1 << endl; // v1 = 2 size_t v2 = 42; auto f1 = [&v2] { return ++v2; }; v2 = 2; auto k = f1(); cout << k << endl; // k = 3 cout << v2 << endl;// v2 = 3 return 0; }
这里分别输出了调用lambda表达式的值和被捕获的值。对于值传递,改变了v1的拷贝的值,于是j等于了43,而v1还是42;对于引用传递,由于绑定的原因,对引用的改变,那么被引用的变量的值也会变,所以最后k和v2的值都变成了3。
相关文章推荐
- 转:C++ Lambda表达式
- VC10和C++ 0x (1) - lambda表达式
- C++ AMP: 在C++中Lambda表达式
- C++lambda表达式
- C++中的Lambda表达式详解
- C++lambda表达式权威指南
- (转载)C++lambda表达式
- C++中Lambda表达式
- C++ lambda表达式权威指南
- C++ is on the way 11: 函数对象和Lambda表达式
- VC10和C++ 0x (1) - lambda表达式
- C++lambda表达式权威指南
- C++ lambda表达式权威指南
- C++ 11 标准 Lambda表达式
- 【转】VC10和C++ 0x (1) - lambda表达式
- C++ 0x中的Lambda表达式
- C++ 11 Lambda表达式
- C++lambda表达式
- C++ lambda表达式
- c++ 11 新特性 lambda表达式