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<int>(a); // ok

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

#include <iostream> 
using namespace std; 

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

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

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

int main() { 
	cout << "-- func(1)" << endl; 
	func(1); 
	
	cout << "-- func(x)" << endl; 
	int x = 10; 
	func(x); // x本身是左值 
	
	cout << "-- func(std::forward<int>(y))" << endl; 
	int y = 20; 
	func(std::forward<int>(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<int>(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服务期高级架构

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值