保定网站建设技术支持,外贸网站建设信息,wordpress技术支持,从零开始做一个网站需要多少钱目录
一、概述
二、场景 1.深拷贝的类 2.浅拷贝的类 C使用指南 一、概述
// Args是一个模板参数包#xff0c;args是一个函数形参参数包
// 声明一个参数包Args...args#xff0c;这个参数包中可以包含0到任意个模板参数。
template class ...Args
void ShowList(…目录
一、概述
二、场景 1.深拷贝的类 2.浅拷贝的类 C使用指南 一、概述
// Args是一个模板参数包args是一个函数形参参数包
// 声明一个参数包Args...args这个参数包中可以包含0到任意个模板参数。
template class ...Args
void ShowList(Args... args)
{} 其中Args、args只是名称可以自定义。
template class ...XX
void showlist(XX... xx)
{} C11的新特性可变参数模板能够创建可以接受可变参数的函数模板和类模板相比 C98类模版和函数模版中只能含固定数量的模版参数可变模版参数无疑是一个巨大的改 进。像下面这样使用可变参数模板
template class ...Args
void ShowList(Args... args)
{
}int main()
{ShowList();ShowList(abcd);ShowList(1,A);ShowList(2,Z,string(测试));return 0;
} 可变参数模板中对于参数类型还有数量都是不可见的因此我们可以自己实现函数来观察。注意打印个数时其他和可变参数模板相关的函数使用都较以往有所不同。 判断参数的数量
template class ...Args
void ShowList(Args... args)
{cout sizeof...(args) endl;
}int main()
{ShowList();ShowList(abcd);ShowList(1,A);ShowList(2,Z,string(测试));return 0;
} 但是不能打印参数下面是错误的代码
template class ...Args
void ShowList(Args... args)
{for (size_t i 0; i sizeof...(args); i){cout args[i] ;}cout endl;
}在这里要区分一下像这样打印参数是在程序运行的时候由于运行过程中变量i在变化可以解析出参数。但是可变参数模板也是模板而模板解析参数是在编译时进行的也就是说在编译结束时参数包里的参数类型和个数都是要确定好的不能等到运行时再解析参数。 因此为了解析参数可变参数模板使用递归的方式展开参数包
// 编译时递归的返回条件
void _ShowList()
{cout endl;
}// 如果想依次拿到每个参数类型和值编译时使用递归解析参数
template class T, class ...Args
void _ShowList(const T val, Args... args)
{cout val ;_ShowList(args...);
}template class ...Args
void ShowList(Args... args)
{_ShowList(args...);
}拿这一行代码举例递归解析参数时可变参数模板实例化出来的函数有下面这些
ShowList(2,Z,string(测试));
//递归的结束条件
void _ShowList()
{cout endl;
}//实例化以后推演生成的过程
void ShowList(int val1, char ch, std::string s)
{_ShowList(val1, ch, s);
}void _ShowList(const int val, char ch, std::string s)
{cout val ;_ShowList(ch, s);
}void _ShowList(const char val, std::string s)
{cout val ;_ShowList(s);
}void _ShowList(const std::string val)
{cout val ;_ShowList();
}二、场景 可变参数模板到底在哪些地方使用 C11在一些常见的容器中实现了带emplace这种字眼的函数 这个函数的功能和push_back类似但是也有不同的地方。下面就来一一对比 1.深拷贝的类 对于类中存在深拷贝即在堆上开辟了空间的类这种类中实现了移动构造函数。 如果使用push_back和emplace_back的传参为有名对象二者是没有任何区别的
listbit::string lt1;bit::string s1(xxxx);
lt1.push_back(s1);
lt1.push_back(move(s1));
cout endl;bit::string s2(yyyy);
lt1.emplace_back(s2);
lt1.emplace_back(move(s2));
cout endl; listpairbit::string, bit::string lt2;pairbit::string, bit::string kv1(xxxx, yyyy);
lt2.push_back(kv1);
lt2.push_back(move(kv1));
cout endl;pairbit::string, bit::string kv2(xxxx, yyyy);
lt2.emplace_back(kv2);
lt2.emplace_back(move(kv2));
cout endl; 如果传参为匿名对象也是没有区别的这里就不举例了。但是如果直接传对象参数的值两者是有区别的
lt1.push_back(xxxx);
lt1.emplace_back(xxxx);
cout endl; 不难看出emplace相比push少了一次移动拷贝。 而list的结点为pair这种复合类型时push_back不能直接传参数的值。只能使用emplace_back因为这些值会被识别为参数包可以编译通过。而push_back的参数类型只能是对象的类型左值或右值
lt2.emplace_back(xxxx, yyyy);
cout endl; 可以总结一点对于存在移动构造函数的类emplace_back相比push_back在调用函数时直接传对象参数的值可以减少一次移动构造函数的调用。 2.浅拷贝的类 如果一个类没有在堆上申请开辟空间这样的类被称为浅拷贝的类这种类中不存在移动构造函数。 同样的如果使用push_back和emplace_back传参为有名对象和匿名对象二者是没有任何区别的
listDate lt1;Date d1(2023, 1, 1);lt1.push_back(d1);
lt1.emplace_back(d1);cout endl;lt1.push_back(Date(2023, 1, 1));
lt1.emplace_back(Date(2023, 1, 1)); 如果直接传对象参数的值二者是有区别的
listDate lt1;
lt1.push_back({ 2024,3,30 });// 不支持
//lt1.emplace_back({ 2024,3,30 });// 推荐
lt1.emplace_back(2024, 3, 30); 可以看出emplace_back相比之下少了一次拷贝构造函数的调用。 同时要注意在这种直接传具体的值传参调用的时候{值}这种写法是不支持emplace的因为emplace的形参是参数包而{值}会被识别为一个初始化列表类型因此在传参完成后参数包被解析为一个初始化列表类型不能用来构造三个参数的构造函数。 经过上面分析总结可变参数模板的使用 在直接给出对象的值的传参情况下emplace系列的函数相比push函数有以下优势 如果是深拷贝的类可以减少一次移动构造函数的调用 如果是浅拷贝的类可以减少一次拷贝构造函数的调用