目录
一,引用
在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关键字 可以使得传值捕捉的参数可以被修改。但并不会影响原参数。