栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

c++11新特性——forward和Lambda

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c++11新特性——forward和Lambda

一、forward

作用:完美转发,参数在传递过程中,保持原有的属性。即参数原来是左值,则传递之后仍然是左值,若是右值,则传递之后仍然是右值。

在学习forward之前,我们先看一个例子:

int &&a = 5;
// a = 50; // 修改成功
int &&right_ref = a; // 错误

分析:这里a是一个右值引用,指向右值5。 但是,a本身是个左值(如果这里不理解,复习下我之前的文章左值右值)。用右值引用指向左值是不对的。那么,如何保持a自身右值引用的特性呢?forward就是干这个的。

int &&a = 5;
// a = 50; // 修改成功
int &&right_ref = std::forward(a); // ok

下面我们再通过例子来看下:

#include  
using namespace std; 

template  
void Print(T &t) { cout << "L" << t << endl; }

template  
void Print(T &&t) { cout << "R" << t << endl; }

template  
void func(T &&t) { 
	Print(t); 
	Print(std::move(t)); 
	Print(std::forward(t)); 
}

int main() { 
	cout << "-- func(1)" << endl; 
	func(1); 
	
	cout << "-- func(x)" << endl; 
	int x = 10; 
	func(x); // x本身是左值 
	
	cout << "-- func(std::forward(y))" << endl; 
	int y = 20; 
	func(std::forward(y)); // 
	return 0; 
}

运行结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/1462219cabb54488ae735871b91ad771.png

二、匿名函数Lambda 2.1 定义

lambda表达式可以看成是一般函数的函数名被略去,返回值使用了一个 -> 的形式表示。唯一与普通函数不同的是增加了“捕获列表”。

2.2 语法格式
int main() { 
	[捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 { 
		// 函数体 
	}
	auto Add = [](int a, int b)->int { return a + b; };
	std::cout << Add(1, 2) << std::endl; //输出3 
	return 0; 
}
2.3 捕获列表

有时候需要在匿名函数体内部使用外部变量,lambda表达式使用捕获列表来传递参数,根据传参的行为,分为:
2.3.1 值捕获
与参数传递类似,值捕获的前提是变量可以拷贝,不同点是,拷贝发生在lambda表达式被创建时,而非调用时。匿名函数体内部不能修改外部变量的值。

void func() { 
	cout << "func" << endl; 
	int c = 12; 
	int d = 30; 
	// 创建时就已经把c、d的值拷贝进去了,所以输出:d = 30;
	auto Add = [c, d](int a, int b)->int { 
		// c = 100; // 编译报错
		cout << "d = " << d << endl; 
		return c; 
	};
	d = 20; 
	std::cout << Add(1, 2) << std::endl; 
}

2.3.2 引用捕获
匿名函数体内部可以修改外部变量。

void func() { 
	cout << "func" << endl; 
	int c = 12; 
	int d = 30; 
	// 创建时就已经把c、d的值拷贝进去了
	auto Add = [&c, &d](int a, int b)->int { 
		c = 100; // 编译ok
		cout << "d = " << d << endl; 
		return c; 
	};
	d = 20; // 因为是引用捕获,且这里修改了d的值,所以输出:20
	std::cout << Add(1, 2) << std::endl; 
}

2.3.3 隐式捕获
手动书写捕获列表,有时候会很复杂。我们可以交给编译器去完成,在捕获列表中写一个 & 或者 = ,向编译器声明是引用捕获还是值捕获。

	auto Add = [&](int a, int b)->int { 
		c = 100; // 编译ok
		cout << "d = " << d << endl; 
		return c; 
	};

2.3.4 [] 空捕获列表
表明不能使用外部变量。

	auto Add = [](int a, int b)->int { 
		c = 100; // 编译报错
		cout << "d = " << d << endl; 
		return c; // 编译报错
	}; 

2.3.5 表达式捕获
上面4种,值和引用捕获都是捕获的已经在外部作用域声明的变量,因此这些捕获的方式均为左值。c++14之后,支持捕获右值,允许捕获的成员用任意的表达式进行初始化。

// C++14 支持表达式捕获
void func() { 
	cout << "func" << endl; 
	auto important = std::make_unique(1); 
	auto add = [v1 = 1, v2 = std::move(important)](int x, int y) -> int { 		
		return x + y + v1 + (*v2); 
	};
	std::cout << add(3,4) << std::endl;
}

2.3.6 泛型Lambda
在c++14之前,Lambda表达式的形参必须执行具体的类型。从c++14开始,支持auto泛型形参。

//泛型 Lambda C++14 
void func() { 
	cout << "func" << endl; 
	auto add = [](auto x, auto y) { return x+y; };
	std::cout << add(1, 2) << std::endl; 
	std::cout << add(1.1, 1.2) << std::endl; 
}

2.3.7 可变Lambda

  • 采用值捕获的方式,lambda不能修改其值,如果想要修改,使用mutable修饰;
  • 采用引用捕获的方式,lambda可以直接修改其值

文章参考与<零声教育>的C/C++linux服务期高级架构。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1027127.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号