文章目录
- 可变参数模板
可变参数模板
-
参数包代表多个类型和参数
// Args是一个模板参数包,args是一个函数形参参数包 // 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。 template <class ...Args> void ShowList(Args... args) {} //使用 int main() {ShowList(1);ShowList(1,2,3.613);ShowList("1111",3,2,'c',vector<int>({111}));//... }
-
查看参数包的参数个数
- 使用
sizeof
,sizeof关键字也是在编译时就就行处理的template <class ...Args> void ShowList(Args... args) {cout << sizeof...(args) << endl; } //使用 int main() {ShowList(1);ShowList(1,2,3.613);ShowList("1111",3,2,'c',vector<int>({111}));//... }
- 使用
-
打印参数包内容
-
编译时递归推导
因为是编译时递归推导,因此不能走运行时逻辑。//下面注释的这个是不行的,因为if语句里的逻辑是运行时的逻辑和处理,而这里的是编译时递归推导,是编译时进行的 //template <class T, class ...Args> //void Print(T&& x, Args&&... args) //{ // cout << x << " "; // Print(args...); // if(sizeof...(args...) == 0) // return; //}//当没参数的时候就调用该函数了 void Print() {cout << endl; }// x存储传入Print参数包的第一个参数 template <class T, class ...Args> void Print(T&& x, Args&&... args) {cout << x << " ";Print(args...); }// 编译时递归推导解析参数 template <class ...Args> void ShowList(Args&&... args) {Print(args...); }
这里和寻常递归不一样,这里是编译时递归推导
-
演示编译时递归推导生成的函数
// 编译器推导的 void Print(int x, const char* y, double z) {cout << x << " ";Print(y, z); }void Print(const char* x, double z) {cout << x << " ";Print(z); }void Print(double x) {cout << x << " ";Print(); } //如果不显示写Print();,那么编译时推导的Print();如下。很明显函数内没有x,会导致编译时报错。 如果最开始的函数模板内没有 cout << x << " ";语句。那么会接着推导出第二个Print();从而导致 有两个Print();函数,导致编译报错。 void Print() {cout << x << " ";Print(); }// 编译时递归推导解析参数 template <class ...Args> void ShowList(Args&&... args) {Print(args...); } // 编译器实例化生成 void ShowList(int x, const char* y, double z) {Print(x, y, z); }int main() {ShowList(1, "xxxxx", 2.2);return 0; }
可见每次走的函数都是不同的函数。而运行时推导是对同一个函数进行多次调用,传入不同数据
-
-
展开函数
语法: 函数名(形参名)…template <class T> int PrintArg(T t) {cout << t << " ";return 0; }template <class ...Args> void ShowList(Args... args) {int arr[] = { PrintArg(args)... };cout << endl; }// 编译推演生成下面的函数 void ShowList(int x, char y, std::string z) {int arr[] = { PrintArg(x),PrintArg(y),PrintArg(z) };cout << endl; }
-
-
可变参数模板中使用完美转发样例
template <class... Args> void emplace_back(Args&&... args) {insert(end(), std::forward<Args>(args)...); }
-
-
介绍emplace_back接口
emplace_back的功能和push_back一样。这里的参数包不是说能一下子push进去好几个数据,而是说当存储的数据为一个需要构造的时候,通过不断向下传这个参数包,使得可以直接构造出要push的数据,效率更高。
- 样例
// emplace_back总体而言是更高效,推荐使用 int main() {bit::list<bit::string> lt;// 左值bit::string s1("111111111111");lt.emplace_back(s1);// 右值lt.emplace_back(move(s1));// 直接把构造string参数包往下传,直接用string参数包构造string。是在emplace_back中new参数包,通过参数包下传,直接构造出了string参数。lt.emplace_back("111111111111");//如果是push_back("111111111111");的话,是先构造string,然后push_back中又new了一个string对象lt.emplace_back(10, 'x');cout << endl << endl;bit::list<pair<bit::string, int>> lt1;// 构造pair + 拷贝/移动构造pair到list的节点中data上pair<bit::string, int> kv("苹果", 1);lt1.emplace_back(kv);lt1.emplace_back(move(kv));cout << endl << endl;// 直接把构造pair参数包往下传,直接用pair参数包构造pairlt1.emplace_back("苹果", 1);return 0; }
- 样例