例如:
struct pt
{
int x;
int y;
}
int main()
{
int a1 = { 7 };
double d1 = { 26.3 };
set<int> st1= { 71 };
pt pos1={ 3, 4 };
//......
//=可省略
int a2{ 7 };
double d2{ 26.7 };
set<int> st2{ 78 };
pt pos2{ 3, 4 };
//......
return 0;
}上⾯的初始化已经很⽅便,但是对象容器初始化还是不太⽅便,⽐如⼀个vector对象,想⽤N个值去构造初始化,那么我们得实现很多个构造函数才能⽀持。
C++11库中提出了⼀个std::initializer_list的类
例如:
int main()
{
vector<int> arr{ 1,5,2,62,4 };
unordered_map<char, int> mp{ {'a',1},{'p',8},{'v',8} };
//可以任意传多个值,在此之前编译器是不能确定你要传入多少个值的,
//所以底层用了std::initializer_list从而支持初始化多个值
return 0;
}C++11⽀持可变参数模板,也就是说⽀持可变数量参数的函数模板和类模板,可变数⽬的参数被称为参数包,存在两种参数包:模板参数包,表⽰零或多个模板参数;函数参数包:表⽰零或多个函数参数。
也就是模板的参数个数是不确定的,当使用它的时候它会根据传入参数的个数自动去推导并生成对应的参数个数的函数或类。
template <class... Args> void Func(Args... x) {}
template <class... Args> void Func(Args&... x) {}
template <class... Args> void Func(Args&&... x) {}我们⽤省略号来指出⼀个模板参数或函数参数的表⽰⼀个包,在模板参数列表中,class...或 typename...指出接下来的参数表⽰零或多个类型列表;在函数参数列表中,类型名后⾯跟...指出 接下来表⽰零或多个形参对象列表;函数参数包可以⽤左值引⽤或右值引⽤表⽰,跟前⾯普通模板 ⼀样,每个参数实例化时遵循引⽤折叠规则。 可变参数模板的原理跟模板类似,本质还是去实例化对应类型和个数的多个函数。 这⾥我们可以使⽤sizeof...运算符去计算参数包中参数的个数。
包扩展就是一个将包里的元素取出来的操作,因为考虑到很多因数,在这个取这些元素过程会比较复杂。
注意:包扩展是在编译时完成的。
如下一个包开展过程:

C++11以后STL容器新增了empalce系列的接⼝,empalce系列的接⼝均为模板可变参数,功能上兼容push和insert系列,但是empalce还⽀持新玩法,假设容器为container<T>,empalce还⽀持直接插⼊构造T对象的参数,这样有些场景会更⾼效⼀些,可以直接在容器空间上构造T对象。

在原来C++类中6个默认成员函数:构造函数、析构函数、拷⻉构造函数、拷⻉赋值重载、取地址重载、const取地址重载的基础上C++11新增了2个默认成员函数,移动构造函数和移动赋值运算符重载。
关键字功能:
default:强行生成默认成员函数。只需在需要编译器生成的默认成员函数声明加上=default即可。如下:
class student
{
public:
student(const string& s, const int& num)
:_name(s),_age(num){}
student() = default;
~student() = default;
private:
string _name;
int _age;
};delete:如果能想要限制某些默认函数的⽣成,在C++98中,是该函数设置成private,并且只声明补丁已,这样只要其他⼈想要调⽤就会报错。在C++11中更简单,只需在该函数声明加上=delete即可,该语法指⽰编译器不⽣成对应函数的默认版本,称=delete修饰的函数为删除函数。例如:
class student
{
public:
student(const string& s, const int& num) = delete;
private:
string _name;
int _age;
};final:(1).防止类被继承。(2).防止函数被重写。
override:检查函数重写是否正确。
lambda 表达式本质是⼀个匿名函数对象,跟普通函数不同的是他可以定义在函数内部。 lambda 表达式语法使⽤层⽽⾔没有类型,所以我们⼀般是⽤auto或者模板参数定义的对象去接收 lambda 对象。 lambda表达式的格式:
[捕捉列表]->返回类型 {函数体} 一个简单的lambda表达式:
auto add1 = [](int x, int y)->int {return x + y; };
cout << add1(1, 2) << endl;
//捕捉列表和参数可为空
//返回值可以省略,可以通过返回对象⾃动推导
//如下:
auto add2 = [](int x, int y){return x + y; };
cout << add2(1, 2) << endl;lambda 表达式中默认只能⽤ lambda 函数体和参数列表中的变量,如果想⽤外层作⽤域中的变量就需要进⾏捕捉。其中捕捉方式有三种,如下:
lambda 表达式如果在函数局部域中,他可以捕捉 lambda 位置之前定义的变量,不能捕捉静态局部变量和全局变量,静态局部变量和全局变量也不需要捕捉, lambda 表达式中可以直接使 ⽤。这也意味着 lambda 表达式如果定义在全局位置,捕捉列表必须为空。 默认情况下, lambda 捕捉列表是被const修饰的,也就是说传值捕捉的过来的对象不能修改,mutable加在参数列表(注意不是捕捉列表)的后⾯可以取消其常量性,也就说使⽤该修饰符后,传值捕捉的对象就可以修改了,但是修改还是形参对象,不会影响实参。使⽤该修饰符后,参数列表不可省略(即使参数为空)。
lambda底层确实是仿函数对象,也就说我们写了⼀个lambda 以后,编译器会⽣成⼀个对应的仿函数的类。仿函数的类名是编译按⼀定规则⽣成的,保证不同的 lambda ⽣成的类名不同,lambda参数/返回类型/函数体就是仿函数operator()的参数/返回类型/函数体, lambda 的捕捉列表本质是⽣成的仿函数类的成员变量。
所以为了方便或增加可读性我们通常都会用lambda来代替仿函数或函数指针。
std::function是⼀个类模板,也是⼀个包装器被定义<functional>头⽂件中。 std::function 的实例对象可以包装存储其他的可以调⽤对象,包括函数指针、仿函数、 lambda 、 bind 表达式等,存储的可调⽤对象被称为std::function的⽬标。若std::function不含⽬标,则称它为空。调⽤空std::function的⽬标导致抛出异常。 函数指针、仿函数、 lambda 等可调⽤对象的类型各不相同, std::function的优势就是统⼀类型,对他们都可以进⾏包装,这样在很多地⽅就⽅便声明可调⽤对象的类型。
语法格式如下:
function<返回类型(参数类型1,参数类型2,......)> 对象名 = 函数指针/仿函数/ lambda / bind 表达式。
示例:
#include<iostream>
#include<functional>
using namespace std;
int add(int x, int y)
{
return x + y;
}
int main()
{
function<int(int, int)> fn = [](int x, int y) {return x + y; };
function<int(int, int)> fm = add;
//......
return 0;
}例如下面这个题可以这么写:
class Solution {
public:
int evalRPN(vector<string>& tokens)
{
stack<int> st;
unordered_map<string,function<int(int,int)>> mp=
{
{"+",[](int x,int y){return x+y;}},
{"-",[](int x,int y){return x-y;}},
{"*",[](int x,int y){return x*y;}},
{"/",[](int x,int y){return x/y;}}
};
for(int i=0;i<tokens.size();i++)
{
if(mp.count(tokens[i]))
{
int a=st.top();st.pop();
int b=st.top();st.pop();
st.push(mp[tokens[i]](b,a));
}
else st.push(stoi(tokens[i]));
}
return st.top();
}
};bind的使用语法:
auto f=bind(可调用对象,参数1,参数2,......)
bind是⼀个函数模板,它也是⼀个可调⽤对象的包装器,可以把他看做⼀个函数适配器,对接收的可调用对象进⾏处理后返回⼀个可调⽤对象。 bind可以⽤来调整参数个数和参数顺序。 bind 也在<functional>这个头⽂件中。 调⽤bind的⼀般形式: auto newCallable = bind(callable,arg_list); 其中newCallable本⾝是⼀个可调⽤对象,arg_list是⼀个逗号分隔的参数列表,对应给定的callable的参数。当我们调⽤newCallable时,newCallable会调⽤callable,并传给它arg_list中的参数。 arg_list中的参数可能包含形如_n的名字,其中n是⼀个整数,这些参数是占位符,表⽰ newCallable的参数,它们占据了传递给newCallable的参数的位置。数值n表⽰⽣成的可调⽤对象 中参数的位置:_1为newCallable的第⼀个参数,_2为第⼆个参数,以此类推。_1/_2/_3....这些占 位符放到placeholders的⼀个命名空间中。如下:
#include<iostream>
#include<functional>
using namespace std;
using placeholders::_1;
using placeholders::_2;
int sub(int x, int y)
{
return x - y;
}
int main()
{
//可以调换传参顺序
auto fn1 = bind(sub, _1, _2);
auto fn2 = bind(sub, _2, _1);
cout << fn1(2, 3) << endl;//输出-1
cout << fn2(2, 3) << endl;//输出1
//可以固定某些参数
auto fn3 = bind(sub, 2, _1);
auto fn4 = bind(sub, _1, 3);
cout << fn3(1) << endl;
cout << fn4(5) << endl;
return 0;
}