C++--可变参数模板和lambda

目录

一,引用

二,可变参数模板

empalce系类

三,lambda

捕捉列表


一,引用

在C++11之后引入可变模板参数支持可变数量的函数模板和类模板。其中这里面的参数称作参数包。语法格式如下:

总体上来看,可变参数模板和之前的模板用法基本上一致。下面举个例子:

cpp 复制代码
template <class ...Args>
void func(Args... args)
{

}

二,可变参数模板

在上述例子中,首先认识了一下什么叫做可变参数模板。其中可以使用sizeof...运算符来计算参数的个数。例如:

cpp 复制代码
template <class ...Args>
void func(Args... args)
{
	cout << sizeof...(args) << endl;
}
int main()
{
	func(1, 2, 3, "fsafa", 2.2);
	return 0;
}

上述代码中有五个参数。


下面来介绍一下包扩展,如上述func例子中,如何将func中的参数打印出来,就需要将这个参数包展开。如下:

cpp 复制代码
void fun1()
{
	cout << endl;
}
template<class T, class ...Args>
void fun1(T x, Args... args)
{
	cout << x << endl;
	fun1(args...);
}
template <class ...Args>
void func(Args... args)
{
	cout << sizeof...(args) << endl;
	fun1(args...);
}

在编译时,每次将参数包中的第一个参数类型给T,剩下的参数打包给Args。因此先打印第一个参数。之后依次类推。当没有参数时,调用第一个fun1 。

注意:此过程为编译时递归,并不是运行时递归。在编译的过程中,编译器已经把此代码进行展开。


empalce系类

在学习了可变参数模板之后,就会发现不管是list,还是vector等等,都多了empalce系类。例如:

这里将一下emplace系类和push系类的区别:

在传入value_type类型的对象时,不管是传入左值还是右值都没有区别。

当传入常量需要隐式类型转化时就有区别。如下:

cpp 复制代码
list<string> lt;
string s1("111111111");
lt.emplace_back("111111111111");
lt.push_back("111111111111");

此时需要注意push_back需要传入的参数时参数类型是定义的类型。如上述list<string>类型是string,因此push_back传入"111111111"需要先进行隐式类型转化。转化成string类型对象。之后通过移动构造构造list的string节点。

emplace系类的参数类型可变参数模板,并没有要求参数类型,因此在传入"1111111111"时,编译器会识别类型为const char* 直接向下传递。并且以const char* 的类型 直接构造 string。

三,lambda

lambda是一个匿名函数对象,可以定义在函数内部,一般适用于小型函数,有时可以替代仿函数使用。lambda的语法格式如下:

表达式返回类型由编译器生成,一般来说由auto接收。

捕捉列表不能为空,下面进行详细讲解

函数返回类型可以为空,若明确返回类型可以由编译器自己生成。

函数体和普通函数的函数体类型,函数体为空时也不能不写。


捕捉列表

在lambda中,默认只能用参数列表的变量,如果想要使用lambda作用域以外的变量就需要进行捕捉。首先捕捉列表不能捕捉全局变量。捕捉分为传值捕捉,传引用捕捉。例如:

cpp 复制代码
int main()
{
	int a = 2;
	int b = 4;
	auto it = [a, &b](int x, int y)->int
		{
			return  x + y + a;
			//a++;
		};
	return 0;
}

a表示传值,b表示传引用。传值捕捉不可以修改。


第二种捕捉为隐式捕捉,分别为=表示传值捕捉;&表示传引用捕捉。例如:

cpp 复制代码
int main()
{
	int a = 2;
	int b = 4;
	auto it = [=](int x, int y)->int
		{
			return  x + y + a;
			//a++;
		};
	auto it2 = [&](int x, int y)->int
		{
			return  x + y + b;
			//a++;
		};
	return 0;
}

当函数体需要那个变量就捕获哪个变量。


第三种捕捉方式为混合捕捉,其中的个别变量需要传值捕捉,其余都是传引用捕捉时或者个别变量需要传引用捕捉,而个别变量传值捕捉。例如:

cpp 复制代码
int main()
{
	int a = 2;
	int b = 4;
	int c = 3;
	int d = 6;
	auto it = [=,&c,&d](int x, int y)->int
		{
			return  x + y + a+d;
			//a++;
		};
	auto it2 = [&,a,b](int x, int y)->int
		{
			return  x + y + b+d;
			//a++;
		};
	return 0;
}

这里需要注意的是,要先写隐式捕捉。顺序不能写错。

总结 :传值捕捉相当于是一种const拷贝因此不能修改。而传引用不会进行拷贝,因此可以进行修改,当lambda里面进行修改之后,原参数也会进行改变。mutable关键字 可以使得传值捕捉的参数可以被修改。但并不会影响原参数。

相关推荐
坚持学习前端日记17 小时前
桌面端与移动端JS桥技术对比及跨平台实现
开发语言·javascript·harmonyos
方也_arkling17 小时前
【八股】JS中的事件循环
开发语言·前端·javascript·ecmascript
你怎么知道我是队长17 小时前
C语言---函数指针和回调函数
c语言·开发语言
坚持学习前端日记17 小时前
原生Android开发与JS桥开发对比分析
android·开发语言·javascript
jiunian_cn17 小时前
【C++11】C++11重要新特性详解
开发语言·c++
何中应17 小时前
windows安装python环境
开发语言·windows·python
tbRNA17 小时前
C/C++ 内存管理
c语言·c++
zh_xuan17 小时前
kotlin 测试if表达式、数组等
开发语言·kotlin
问道飞鱼17 小时前
【Rust编程】Cargo 工具详解:从基础到高级的完整指南
开发语言·后端·rust·cargo