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

网站开发过程淘客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/a/497065.html

相关文章:

  • 哪个网站可以做竖屏网站的模版可以换吗
  • 门户网站有哪几个湛江赤坎海田网站建设招聘
  • LangGraph 源码学习总结 1-Graph结构
  • 电子商务网站建设需要多少钱学电商有前途吗
  • 【星海随笔】数据的表示与运算
  • 【知识点总结】Vue2 与 Vue3 区别
  • 平度网站整站优化外包公司php网站数据库修改
  • 机器学习-强化学习
  • 网站开发英文论文资料百度短网址生成
  • 直播功能开发怎么优化网站排名具体怎么做
  • 每日一个C语言知识:C 指针
  • 详解窗口函数中的RANGE BETWEEN子句
  • 30、Linux 磁盘基本原理、管理
  • ps如何做网站首页阿里 wordpress 安装
  • 淘宝客聚惠购的网站怎么做网站浏览历史怎么查看
  • Python 常用模块
  • 卫星授时原理
  • 2025时空低空经济发展现状与智能化趋势
  • 哪个网站推广做的好做网站素材在哪找
  • 荆州公司做网站多仓库版仓库管理网站建设源码
  • 哈尔滨餐饮网站建设外包公司的人好跳槽吗
  • 高中课程免费教学网站网络规划设计师知识点
  • 企业官方网站制作wordpress 3.8.1 exp 下载
  • 为什么做腾讯网站网站建设方案与报价
  • 网站建设教程特别棒湖南岚鸿权 威工业设计专业最好的大学世界排名
  • 2 网站内部链接优化网址大全
  • 3D Gaussian Splatting论文简要解读与可视化复现(基于gsplat)
  • 养老网站备案必须做前置审批吗天津电商网站建设
  • Spring Data Redis
  • 站长之家工具高清网站的百度推广怎么做