网站建设设计基础温州营销推广公司
web/
2025/10/5 10:25:15/
文章来源:
网站建设设计基础,温州营销推广公司,微信怎么做淘客网站,自己如何做网站推广不要做一个清醒的堕落者文章目录 可变参数模板的简介什么是可变参数 模板参数包参数包数据的获取(函数递归获取)参数包的获取(逗号表达式获取) 可变参数的应用emplace 可变参数模板的简介
c11添加的新特性能够让你创建可以接受改变的函数模板和类模板#xff0c;C98/03#…不要做一个清醒的堕落者文章目录 可变参数模板的简介什么是可变参数 模板参数包参数包数据的获取(函数递归获取)参数包的获取(逗号表达式获取) 可变参数的应用emplace 可变参数模板的简介
c11添加的新特性能够让你创建可以接受改变的函数模板和类模板C98/03类模版和函数模版中只能含固定数量的模版参数可变模版参数无疑是一个巨大的改进。
什么是可变参数
首先我们先来介绍一下什么是可变参数我们先从函数说起吧我们想想可变是什么意思我们在写一个函数的时候我们的函数形参一般数量都是固定的比如Add函数max函数min函数都是只能传递两个参数那么有哪些函数可以传递的形参数目是不固定的呢那当然是printf scanf这两个函数的参数数量都是变化的并且参数类型也是那么这是如何做到的呢其实就是使用了可变参数模板那么printf和scanf的底层其实使用了一个类似于数组的一个东西而惊天我们讲述的则是更为高级些的类的可变参数。
模板参数包
首先我们先说一下格式
// Args是一个模板参数包args是一个函数形参参数包
// 声明一个参数包Args...args这个参数包中可以包含0到任意个模板参数。
template class ...Args
void ShowList(Args... args)
{}这里呢就是它的一个格式。 上面的参数args前面有省略号所以它就是一个可变模版参数我们把带省略号的参数称为“参数 包”它里面包含了0到NN0个模版参数。我们无法直接获取参数包args中的每个参数的只能通过展开参数包的方式来获取参数包中的每个参数这是使用可变模版参数的一个主要特点也是最大的难点即如何展开可变模版参数。由于语法不支持使用args[i]这样方式获取可变参数所以我们的用一些奇招来一一获取参数包的值。
参数包数据的获取(函数递归获取)
那么我们可以通过什么方式呢这里其实比较好的办法是通过函数递归进行展开。 代码如下
#includeiostream
using namespace std;
templateclass T
void func(T val)
{cout val ;
}
templateclass T,class ...Args
void func(T val, Args... args)
{cout val ;func(args...);
}
int main()
{func(1, 2, 3, 4, 5);return 0;
}这里的递归展开图呢我给大家画一下 那么这里呢就是这个函数的递归展开图其实这个args大家如果不理解可以将它看成是一个背包这个背包可以是空的然后可以把数据放进去然后利用函数重载将其一个一个取出来。其次呢我们就是只有一个参数的拿个函数我们称之为终止函数因为有了这个函数才使得当这个背包里只剩下一个数据的时候才能有函数可调用表示终止了。当然了也不止这一个方法。
参数包的获取(逗号表达式获取) 这种展开参数包的方式不需要通过递归终止函数是直接在expand函数体中展开的, printarg不是一个递归终止函数只是一个处理参数包中每一个参数的函数。这种就地展开参数包的方式实现的关键是逗号表达式。我们知道逗号表达式会按顺序执行逗号前面的表达式。expand函数中的逗号表达式(printarg(args), 0)也是按照这个执行顺序先执行printarg(args)再得到逗号表达式的结果0。同时还用到了C11的另外一个特性——初始化列表通过初始化列表来初始化一个变长数组, {(printarg(args), 0)…}将会展开成((printarg(arg1),0), (printarg(arg2),0), (printarg(arg3),0), etc… )最终会创建一个元素值都为0的数组int arr[sizeof…(Args)]。由于是逗号表达式在创建数组的过程中会先执行逗号表达式前面的部分printarg(args)打印出参数也就是说在构造int数组的过程中就将参数包展开了这个数组的目的纯粹是为了在数组构造的过程展开参数包 template class T
void PrintArg(T t)
{cout t ;
}
//展开函数
template class ...Args
void ShowList(Args... args)
{int arr[] { (PrintArg(args), 0)... };cout endl;
}
int main()
{ShowList(1);ShowList(1, A);ShowList(1, A, std::string(sort));return 0;
}这里给大家说明一下这里其实数组后面的三个点是交给编译器去推的也就是说编译器眼里这里是怎们处理了呢
int arr[]{(PrintArg(args), 0),(PrintArg(args), 0),(PrintArg(args), 0)}//是这个样子的那么让我们自己去写肯定是不行的太麻烦所以交给编译器去推导当然了我认为还可以更加简化一些简化为下面这个代码更好
#includeiostream
#includestring
using namespace std;
template class T
int PrintArg(T t)
{cout t ;return 0;
}
//展开函数
template class ...Args
void ShowList(Args... args)
{int arr[] { PrintArg(args)... };cout endl;
}
int main()
{ShowList(1);ShowList(1, A);ShowList(1, A, std::string(sort));return 0;
}首先我们要理解为什么原来的代码要加逗号表达式里面写个0其实是因为数组不能为空所以写的那么我们直接将函数的返回值改为返回0不是也可以解决这个问题吗。
可变参数的应用emplace
emplace的函数声明如下
template class... Args
void emplace_back (Args... args);首先我们看到的emplace系列的接口支持模板的可变参数并且万能引用。那么相对insert和 emplace系列接口的优势到底在哪里呢 我们看一下图中的这个代码我们发现emplace_back这样子插入没有报错而push_back这样却报错了这是为什么呢其实就是因为emplace_back的底层用了可变参数包。我们可以弄一个简易的类来给大家查看一下。
#includelist
#includestring
#includeiostream
using namespace std;
namespace clzyf {class data{private:int year, month, day;public:data(int _year 1, int _month 1, int _day 1):year(_year), month(_month), day(_day){;}templateclass... Argevoid crate(Arge... arge){data(arge);}};
}
int main()
{clzyf::data a { 2023,10,14 };clzyf::data b{2023,10};clzyf::data c{2023};clzyf::data d{};return 0;
}请看这里我们通过传值将参数弄成一个参数包并且设置一下缺省参数这样子传递的话就可以弄出更多的花样,那么我们言归正传在上面的那个例子中其实也是这样的他首先先将传递给emplace的参数弄成一个参数包然后将参数包打包给插入函数因此就可以做到push_back无法做到的事情了。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/87313.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!