lambda表达式-2

        当定义一个lambda时,编译器生成了一个与lambda对应的类类型,这个类类型是未命名的。因此,当向一个函数传递一个lambda时,同时定义了一个类类型以及该类型的一个对象:传递的参数就是该对象。类似的,使用auto定义一个用lambda初始化的变量时,实际上定义了一个lambda生成的类类型对象。

auto f = [] {return 42};

cout << f() << endl;  //打印42   

类似于参数传递,lambda变量的捕获方式也可以是值捕获引用捕获

值捕获

        与参数不同,被捕获的变量的值是在lambda创建时拷贝,而不是调用时拷贝,因此,lambda创建后对值修改,不会影响到lambda内对应的值

int v1 = 42;

auto f = [v1] {return v1;};

v1 = 0;

cout << f() << endl; //输出42,f保存创建时的值

引用捕获

捕获变量时,可以采用引用捕获的方式

int v1 = 42;

auto f = [&v1] {return v1;};

v1 = 0;

cout << f() << endl; //输出0,采用引用捕获变量,而非拷贝

当以引用的方式捕获变量时,必须保证lambda执行时变量是存在的。


隐式捕获

除了显式列出捕获列表之外,还可以采用隐式捕获的方式,让编译器根据lambda体中的代码推断要使用那些变量,捕获变量的方式通过&或=来指定,&表示引用捕获,=表示值捕获。

auto wc = find_if(words.begin(), words.end(),

    [=] (const string &s)) {return s.size() >= sz;};

当一部分采用值捕获,另一部分采用引用捕获时,可以混合使用隐式捕获和显式捕获

for_each(words.begin(), words.end(),

    [&, c] (const string& s) {os << s << c};);   //os隐式捕获, c显式捕获

注意:混合使用隐式和显式捕获时,捕获列表的第一个元素必须时&或=,也就是说,隐式捕获必须放在前面。

          隐式捕获与显式捕获混合使用时,两种捕获的方式必须不同:

                即隐式捕获采用引用捕获,则显式捕获必须采用值捕获,反之亦然。


可变lambda

通过值捕获的变量在lambda体内默认不可修改,如果想要修改,需要加关键字mutable

int = 42;

auto f = [m] () mutable {return ++m};;

cout << f() << endl; //输出43

通过引用捕获的变量是否可以修改依赖于引用的类型是否为const


指定lambda返回类型

lambda体内是单一返回类型时,无需指定返回类型,编译器可以推算出来;

但是lambda体内包含return之外的任何语句时,都必须指定返回类型,否则编译器假定lambda返回void,有时会产生编译错误

例如,将负数替换为绝对值的算法和lambda:

transform(v1.begin(), v1.end(), v1.begin(), [] (int i) {return i < 0 ? -i : i; });  //正确,只有单一的return语句

transform(v1.begin(), v1.end(), v1.begin(), [] (int i) {if(i < 0) return -i; else return i; }); //错误,不能推断返回类型

这时,需要指定返回类型,使用尾置返回类型指定

transform(v1.begin(), v1.end(), v1.begin(),

        [] (int i) -> int {if(i < 0) return -i; else return i;});

注意:以上说明取自《C++ Primer(第5版)》,在VS2015中验证时发现,只要多条return语句返回的类型一致,就可以推断出返回类型,无须指定返回类型;

只有返回类型不一致时,才会产生编译错误:error C3487: “float”: 所有返回表达式必须推导为相同类型: 以前为“int”


猜你喜欢

转载自blog.csdn.net/sg_0208/article/details/79996309