C++ lambda表达式

lambda表达式简介

lambda表达式是C++11新特性(C++11 特性),用于创建一个可调用单元,可理解成匿名内联函数。

可调用单元 是指什么?
可调用单元通常是指可调用对象(或函数)。

可调用对象

一个对象或表达式,如果可对其使用可调用运算符("()"),则称这个对象或表达式为可调用对象。

可调用对象组成
4种:函数, 函数指针, 重载了"()"的类,lambda表达式。
本文主要介绍lambda表达式。

[======]

lambda表达式语法

格式

[捕获列表](参数列表) mutable或exception -> 返回值类型 { 函数体 }

捕获列表

捕获列表可以为空,但"[]"不可用省略,用来标识一个lambda表达式开始。
lambda要访问所在函数的局部变量时,必须先捕获。2种局部变量捕获方式:

  • 值捕获:创建lambda表达式时,拷贝所在函数的局部变量的值。
  • 引用捕获:创建lambda表达式时,获取变量的引用。需要确保lambda使用变量时,变量对应对象存在。

注意:
1)值捕获是发生在lambda创建时,而非调用时。
2)lambda无法捕获任何static变量、全局变量,不过可以在lambda表达式内部直接访问。

// 值捕获拷贝变量,发生在lambda创建时
void func1()
{
	size_t v1 = 10;
	auto a = [v1]()->int { return v1; }; // 值捕获v1 = 10
	v1 = 0;
	auto b = a(); // lambda调用时,不会改变捕获值,因此b为10
}

// 引用捕获获取变量引用
void func2()
{
	size_t v1 = 10;
	auto a = [&v1]()->int { return v1; }; // 引用捕获v1
	v1 = 0;
	auto b = a(); // b为0
}

// lambda访问全局变量、static变量
size_t sz = 10;
static int counter = 0;
void func3()
{
	auto f0 = [sz](int a, int b) { return a > b}; // 错误:lambda无法捕获任何具有静态存储持续时间的变量
	auto f = [](string& x, string& y)->bool {
		counter++; // OK:lambda表达式可以直接访问static变量

		if (x.size() > sz) { // OK:lambda表达式可以直接访问global变量
			return true;
		}
		return x > y; 
	};

	string s1 = "123456";
	string s2 = "abcdefgh";
	auto r = f(s1, s2);

	cout << r << endl; // 打印0
	cout << counter << endl; // 打印1
}

隐式捕获

捕获列表中写“&”,告诉编译器采用引用捕获方式;写“=”,告诉编译器采用值捕获方式。如果有个别局部变量不需要用统一的捕获方式,可以专门指出其捕获方式,然后用逗号方式分隔不同捕获。

string v1 = "abc";
string v2 = "123465";
string v3 = "qwert";

auto f1 = [&](const string& s)->{ cout << v1.size() + s.size() << endl; }; // 引用捕获
auto f2 = [=](const string& s)->{ cout << v2.size() + s.size() << endl; }; // 值捕获
auto f3 = [=, &v1](const string& s)->{ cout << v2.size() + s.size() << endl; }; // 引用捕获v1, 其余都是值捕获
auto f4 = [&, v2, v3](const string& s)->{ cout << v2.size() + s.size() << endl; }; // 值捕获v2, v3, 其余都是引用捕获
f1("test1");
f2("test2");
f3("test3");

参数列表

参数列表 可以为空,但"()"不可用省略。类似于函数定义。

mutable关键字

  • mutable对于const函数作用
    const成员函数中,通常不能修改non-static数据成员。如果要修改,需要将数据成员声明为mutable,表示该变量可变,不再有constness(常量性)约束。
    具体可参见Effective C++ 条款03:尽可能使用const

  • mutable对于lambda作用
    在lambda表达式中,mutable有类似效果,默认不能修改值捕获的变量。
    当lambda要修改值捕获的变量时,必须添加mutable声明。

void fcn()
{
	size_t v1 = 10;
	auto f = [v1]() mutable { return ++v1; }; // 加上mutable才能修改值捕获的v1
	// <=> auto f = [v1]() mutable -> int { return ++v1; }; 
	v1 = 0;
	auto j = f(); // j 为11
}

指定lambda返回类型

默认情况下,
1)如果lambda函数体只包含单一return语句,可以省略lambda返回类型(编译器自动推断返回类型)。
2)如果包含return之外的任何语句,编译器假定此lambda返回void。

简单来说,如果编译器无法推断lambda返回类型,就需要尾置返回类型,不可省略。

例,

vector<int> vec;
... // vec插入数据
	
// OK, 单一return语句, 编译器能推断出lambda的返回类型
transform(vec.begin(), vec.end(), vec.begin(), [](int i) { return i < 0 ? -i : i; }); 

// 错误, 不能推断lambda的返回类型
transform(vec.begin(), vec.end(), vec.begin(), [](int i) -> int { 
	/* 非单一return语句 */
	if (i < 0) return -i; 
	else return i;
});

原文链接: https://www.cnblogs.com/fortunely/p/15417012.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    C++ lambda表达式

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/215014

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月13日 上午2:38
下一篇 2023年2月13日 上午2:39

相关推荐