当前位置: 首页 > wzjs >正文

wordpress小说网站主题营销网站制作公司

wordpress小说网站主题,营销网站制作公司,东莞哪里疫情比较严重,做网站的方案图片前言 可变参数在大家学习C语言之初,写下第一个打印”Hello World“的程序时就接触过了,即printf()。第二个参数 ... ,就是可变参数。 就使用而言,可变参数允许我们一次性传入多个参数,并且类型不限。 但上述可变参数…

前言

可变参数在大家学习C语言之初,写下第一个打印”Hello World“的程序时就接触过了,即printf()。第二个参数 ... ,就是可变参数。

就使用而言,可变参数允许我们一次性传入多个参数,并且类型不限。

但上述可变参数尽针对函数参数,

在C++11中,为了完善泛型编程,引入了可变参数模板,使得模板参数也具备了此特性,能够接受数个不同类型的模板参数。

可变参数模板

语法

形式很简单,只要在模板参数前,带上 ... 就行。

template<class ...Args>  //typename也可;省略号跟在class后也行

...Args就是包含各个参数的参数包,可看作一个形似数组的容器,可以存0个或n个参数,不限类型。(形似数组理解,不是数组是因为数组是相同类型元素的集合)

...Args可以作为函数模板参数包,也可作为类模板参数包。

 比较

C的可变参数是通过4个宏实现的,且如果定义了一个带可变参数的函数,还必须一起传入可变参数的个数。

但C++的可变模板参数不同,...Args参数包可以直接接收任意个数的任意类型的参数。基础原理就仰仗于函数重载和模板。

原理

这里要先介绍一下sizeof...()操作符,其可计算参数包的参数个数。

 为了方便理解其原理,这里介绍函数模板的参数包。

template<class ...Args>
void Print(Args&&... args) {cout << sizeof...(args) << endl;
}int main()
{int x = 1;Print();Print(x);Print(x,2.5);Print(x, 2.5, "Hello");return 0;
}

上文提到其原理仰仗于函数重载和模板

其实就是,模板使用参数,推导出不同参数列表的函数重载。

上面的代码本质如下:

void Print();void Print(int&& x);void Print(int&& x, double&& y);void Print(int&& x, double&& y, string&& z);

但我们还可以想象,如果没有可变模板参数,我们要让编译器推出上面的函数,

就得写下面1个函数 + 3个函数模板

void Print();template<class T>
void Print(T&& t);template<class T1, class T2>
void Print(T1&& t1, T2&& t2);template<class T1, class T2, class T3>
void Print(T1&& t1, T2&& t2, T3&& t3);

可幸亏有了可变模板参数,在类型泛化的基础上叠加了数量变化,使得泛型编程更加灵活。 

包拓展

 但到目前为止,我们对参数包有了一定了解,可是如何从参数包中获取参数并使用呢?

sizeof...()操作符远远不够,我们还需要了解包拓展。

void ShowList() {}template<class T, class ...Args>
void ShowList(T t, Args... args)
{cout << t << " ";ShowList(args...);
}template<class ...Args>
void Print(Args... args) {ShowList(args...);
}int main()
{int x = 1;Print(x, 2.5, "Hello");return 0;
}

 

以上就是包拓展的过程,本质就是用模板帮我们把参数包解构,用 1 + n-1 的函数模板重载 n 个函数,但是要自行处理没有参数的函数重载。

但实际上,这个玩法已经过时了,在C++17中已经有了更高级的玩法,感兴趣可以去看看文档,问问AI。

不过其实还有一种玩法,只不过有点抽象,需要体会。。

template<class T>
const T& getArgs(const T& t)
{cout << t << " ";return t;
}template<class ...Args>
void Arguments(Args... args)
{}template<class ...Args>
void Print(Args... args) {Arguments(getArgs(args)...);//用getArgs的返回值构成Arguments()的参数包
}int main()
{int x = 1;Print(x, 2.5, "Hello");return 0;
}

本质如下


void Print(int x, string y, double z)
{Arguments(getArgs(z), getArgs(y), getArgs(x));
}

怎么是倒序?C++规定是这样的,参数包展开时的求值顺序是从右到左的。 规则是别人定的。

要正序其实还是离不开上一种形似递归(bushi)的方法。

应用(emplace系列)

C++11给STL容器都新增了一个接口emplace

瞩目的点当然就是这个可变参数模板了,怎么好端端的push_back,insert不够香吗?

接下来会以list的emplace_back进行解释。

对比emplace与push系列

一般在定义list时,我们其实都已经确定好了模板参数,如下。

list<string> lt;

那么在push_back时,该函数模板也被实例化为

void push_back(const string& val);lt.push_back("666");

 如上场景中,"666"是一个const char*型的常量字符串,

就需要先隐式类型转换,构造一个string临时对象,再将临时对象拷贝构造给结点数据域的string,最后尾插。

看起来没什么,请看如下场景:

template <class... Args>void emplace_back (Args&&... args);lt.emplace_back("666");

同样是const char*的常量字符串,push_back()由于实例化好了,要进行隐式转换

而emplac_back()只有在调用、接受参数后,编译器才会实例化它,并且参数类型是const char*!

这有差别吗?有的,有的。

有了 const char* 的常量字符串,可以直接再将其传给结点的可变参数模板的构造函数,此时又可以继续将const char* 常量字符串作为参数去直接构造结点的string成员变量,走string(const char* s)的构造,只需要构造一次就够了!

好了,我知道这段话很长很臭,请看下图:

 图中实现了一路将常量字符串传递给了结点string的构造,只要进行一次构造就够了。

而相对于push_back(),还要不断地拷贝构造,这个效率在对比下就体现出来了。

(补充:emplace_back的底层可以理解为又去复用了一个可变参数模板的insert(),中间要用完美转发传递右值参数)

template <class... Args>
void emplace_back(Args&&... args)
{insert(end(), std::forward<Args>(args)...);//!!!
}template <class... Args>
iterator insert(iterator pos, Args&&... args)
{Node* cur = pos._node;Node* newnode = new Node(std::forward<Args>(args)...);//!!!Node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return iterator(newnode);
}

但上述是否能证明emplace系列就一定比push系列、insert()高效呢?

NO。

如果是如下情形,

string s("666");//左值传参
lt.push_back(s);lt.emplace_back(s);//右值传参
lt.push_back((move)s);lt.emplace_back((move)s);

 此时二者的效率就没差别了,都是字符串,要么拷贝构造、要么移动拷贝。

总结

总结一下,emplace系列在接受到构造函数所需参数时,能够直接构造,中间不需要拷贝构造。如此情形下,效率较高;而其他情形的效率没差。(读者可以用list<pair<string, int>>自行感受)

但毕竟emplace存在过人之处,哪怕只有一个,也是过人之处。

所以以后还是推荐用emplace系列。

上述涉及”移动语义“与”右值“的前置知识,建议学完再看emplace部分。。。

----------------------------------------------------------完--------------------------------------------------------------------

http://www.dtcms.com/wzjs/108814.html

相关文章:

  • 衡水企业网站建设费用宁波谷歌优化
  • 山东专业网站解决方案制作考拉seo
  • 哪有做网站的公司如何创建自己的卡网
  • 怎么做钓鱼网站生成器备案查询网
  • 网站app开发费用软文经典案例
  • 电子商务网站建设哪家好百度关键词首页排名怎么上
  • 网站推广经验杂谈百度应用商店app下载
  • 下载类网站模板seo搜索引擎优化是什么意思
  • 网站建设捌金手指下拉七广东深圳龙华区
  • 简易静态网站制作流程图seo诊断工具网站
  • 吴江公司网站建设电话竞价托管代运营公司
  • 网站建设客户合同技能培训有哪些
  • 网站建设与管理专业教学计划移动营销
  • 做招聘网站怎么样精准网站seo诊断报告
  • 广西做网站公司排名外贸网站建设 google
  • 西安网站建设公司有哪些b2b网站大全免费推广
  • 如何让百度快速收录网站文章google免费入口
  • 做业务 哪个网站比较好学前端去哪个培训机构
  • 做网站大概什么价位北京优化网站公司
  • 专门做饥饿营销的网站厦门百度开户
  • 百度地图2020旧版本下载石家庄网站seo外包
  • 建设银行行号网站查询是什么seo网站推广的主要目的
  • 做导购网站用什么样的主机网页设计案例
  • 秦皇岛网站建设服务网络服务器搭建
  • 芜湖的网站建设公司人工在线客服系统
  • 日本网站在线免费观看电视剧seo快速优化排名
  • 益阳做网站权重查询入口
  • 网站怎么做双语种海外网络推广
  • 万江仿做网站网站开发工程师
  • 义乌网站制作多少钱广州seo优化推广