C++ lambda表达式

C++11及之后的lambda表达式是一个强大的工具,它可以表示一个可调用的代码单元。可以理解为一个未命名的内联函数。一个lambda表达式具有如下形式:

[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。

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qxconverse/article/details/69787996