C++lambda函数

文章介绍了C++中的Lambda函数,它简化了代码,允许访问外部变量并创建匿名可调用对象。Lambda函数通过捕获列表可以捕获外部变量,可以按值或引用方式捕获。C++14以后,Lambda函数支持泛型和广义捕获,增强了其灵活性和功能。
摘要由CSDN通过智能技术生成

lambda可以大幅度简化代码,消除因编写可调用对象产生的公式化代码。lambda函数能访问外部调用语境中的本地变量,便捷地表达出自身语义,无须另行设计带有函数调用操作符的类,再借成员变量捕获状态。

lambda通常用于生成匿名的可调用对象,[]内为捕获列表,可以指定捕获方式,()内表示接收的参数,{}内为函数体,以下代码将vector中的元素写到std::cout中:

std::vector<int> data = load_data();//假设load_data()函数获取数据
std::for_each(data.begin(), data.end(), [](int i) {std::cout << i << std::endl; });

若函数体无法仅用一条return语句写成,就需要明确设定返回值,方法是在()后附上箭头(->)和目标返回值型别:

std::condition_variable cond;//条件变量
bool data_ready;
void wait_for_data()
{
	std::unique_lock<std::mutex> lk(m);
	//只有data_ready为true时,wait()的调用才会结束并返回
	cond.wait(lk, []()->bool {
		if (data_ready)
		{
			std::cout << "Data ready!" << std::endl;
			return true;
		}
		else
		{
			std::cout << "Data not ready, resuming wait!" << std::endl;
			return false;
		}
	})
}

捕获本地变量的lambda函数

若要在lambda函数中访问本地变量,则需先将其捕获,最简单的方式是使用引导符“[=]”,即可访问本地变量的副本:

#include<functional>
std::function<int(int)> offseter(int offset)
{
	return [=](int j) {return offset + j; };
}
int main()
{
	std::function<int(int)> offset_52 = offseter(52);
	std::cout << offset_52(10) << std::endl;//返回62
}

除了上述方式捕获本地变量,还可以以引用方式进行捕获“[&]” ,照此处理,一旦lambda函数脱离生成函数或所属代码块的作用域,引用变量就会被销毁,此时若仍调用lambda则会引发未定义行为。

int main()
{
	int offset = 28;
	std::function<int(int)> offset_a = [&](int i) {return offset + i; };
	offset = 50;
	std::function<int(int)> offset_b = [&](int i) {return offset + i; };
	std::cout << offset_a(50) << "," << offset_b(50) << std::endl;
    //输出100, 100
}

若想按复制方式捕获大部分本地变量,针对一两个变量采用索引方式捕获,则应该使用形如“[=]”的lambda引导符,在等号后面逐一列出引用变量:

int main()
{
	int i = 123, j = 456, k = 789;
	std::function<int()> f = [=, &j, &k] {return i + j + k; };
	i = 1;
	j = 2;
	k = 3;
	std::cout << f() << std::endl;
	//输出128(123+2+3)
}

使用[&, j, k]则以复制方式捕获j,k,以引用方式捕获其余变量:

int main()
{
	int i = 123, j = 456, k = 789;
	std::function<int()> f = [&, j, k] {return i + j + k; };
	i = 1;
	j = 2;
	k = 3;
	std::cout << f() << std::endl;
	//输出1246(256+789+1)
}

若要在lambda函数内部访问类的数据成员,则必须在捕获列表上加上this指针以捕获之:

struct C
{
	int some_data;
	void do_something(std::vector<int>&vec)
	{
		std::for_each(vec.begin(), vec.end(),
			[this](int& i) {i += some_data; });
	}
};

上述例子使用this捕获数据成员some_data。

C++14开始,lambda也能有泛型形式,其中的参数被声明为auto,而非具体型别,根据运行时外部提供的参数导出:

	auto f = [](auto x) {std::cout << "x=" << std::endl; };
	f(50);
	f("hello!");

C++14还加入了广义捕获(generalized capture)的概念,因此能够捕获表达式的运算结果,而不再局限于直接复制或引用本地变量,该特性用于以移动方式捕获只移型别

std::future<int> spawn_task()
{
	std::promise<int> p;
	auto f = p.get_future();
	std::thread t([p = std::move(p)](){p.set_value(find_the_answer();)});
	t.detach();
	return f;
}

p=std::move(p)就是广义捕获行为,将promise实例移入lambda函数,因此线程可以安全地分离,不必担心因为本地变量被销毁形成悬空引用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值